[mapguide-commits] r8394 - in trunk/MgDev: . Common/MapGuideCommon/MapLayer Common/MapGuideCommon/Services Common/PlatformBase/MapLayer Common/PlatformBase/Services Desktop Desktop/MgDesktop Desktop/MgDesktop/MapLayer Desktop/MgDesktop/Services Desktop/MgDesktop/Services/Feature Desktop/MgDesktop/Services/Feature/Commands Desktop/Samples/SampleExtension Desktop/UnitTest Server/src/Services/Feature Server/src/UnitTesting UnitTest/WebTier/DotNet/MgTestRunner UnitTest/WebTier/DotNet/TestCommon UnitTest/WebTier/DotNet/TestCommon/ExternalTests UnitTest/WebTier/DotNet/TestCommon/Properties UnitTest/WebTier/DotNet/TestMapGuideApi UnitTest/WebTier/DotNet/TestMapGuideApi/ExternalTests UnitTest/WebTier/DotNet/TestMapGuideApi/Properties Web/src/DotNetUnmanagedApi/PlatformBase Web/src/MapGuideApi

svn_mapguide at osgeo.org svn_mapguide at osgeo.org
Tue Oct 7 18:36:51 PDT 2014


Author: jng
Date: 2014-10-07 18:36:51 -0700 (Tue, 07 Oct 2014)
New Revision: 8394

Added:
   trunk/MgDev/Server/src/Services/Feature/OpDeleteFeatures.cpp
   trunk/MgDev/Server/src/Services/Feature/OpDeleteFeatures.h
   trunk/MgDev/Server/src/Services/Feature/OpInsertFeatures.cpp
   trunk/MgDev/Server/src/Services/Feature/OpInsertFeatures.h
   trunk/MgDev/Server/src/Services/Feature/OpInsertFeaturesBatched.cpp
   trunk/MgDev/Server/src/Services/Feature/OpInsertFeaturesBatched.h
   trunk/MgDev/Server/src/Services/Feature/OpUpdateMatchingFeatures.cpp
   trunk/MgDev/Server/src/Services/Feature/OpUpdateMatchingFeatures.h
   trunk/MgDev/Server/src/Services/Feature/TransformedGeometryFeatureReader.cpp
   trunk/MgDev/Server/src/Services/Feature/TransformedGeometryFeatureReader.h
   trunk/MgDev/UnitTest/WebTier/DotNet/TestCommon/ExternalTests/ConvenienceTests.cs
   trunk/MgDev/UnitTest/WebTier/DotNet/TestCommon/Properties/Resources.Designer.cs
   trunk/MgDev/UnitTest/WebTier/DotNet/TestCommon/Properties/Resources.resx
   trunk/MgDev/UnitTest/WebTier/DotNet/TestCommon/Resources/
   trunk/MgDev/UnitTest/WebTier/DotNet/TestMapGuideApi/ExternalTests/ResourceServiceTests.cs
   trunk/MgDev/UnitTest/WebTier/DotNet/TestMapGuideApi/Properties/Resources.Designer.cs
   trunk/MgDev/UnitTest/WebTier/DotNet/TestMapGuideApi/Properties/Resources.resx
   trunk/MgDev/UnitTest/WebTier/DotNet/TestMapGuideApi/Resources/
Modified:
   trunk/MgDev/
   trunk/MgDev/Common/MapGuideCommon/MapLayer/Layer.cpp
   trunk/MgDev/Common/MapGuideCommon/MapLayer/Layer.h
   trunk/MgDev/Common/MapGuideCommon/Services/ProxyFeatureService.cpp
   trunk/MgDev/Common/MapGuideCommon/Services/ProxyFeatureService.h
   trunk/MgDev/Common/PlatformBase/MapLayer/LayerBase.cpp
   trunk/MgDev/Common/PlatformBase/MapLayer/LayerBase.h
   trunk/MgDev/Common/PlatformBase/Services/FeatureDefs.h
   trunk/MgDev/Common/PlatformBase/Services/FeatureService.h
   trunk/MgDev/Common/PlatformBase/Services/ResourceDefs.h
   trunk/MgDev/Common/PlatformBase/Services/ResourceService.h
   trunk/MgDev/Desktop/
   trunk/MgDev/Desktop/MgDesktop/MapLayer/Layer.cpp
   trunk/MgDev/Desktop/MgDesktop/MapLayer/Layer.h
   trunk/MgDev/Desktop/MgDesktop/MgDesktop.vcxproj
   trunk/MgDev/Desktop/MgDesktop/Services/Feature/Commands/UpdateFeatures.cpp
   trunk/MgDev/Desktop/MgDesktop/Services/Feature/Commands/UpdateFeatures.h
   trunk/MgDev/Desktop/MgDesktop/Services/Feature/RasterHelper.cpp
   trunk/MgDev/Desktop/MgDesktop/Services/Feature/RasterHelper.h
   trunk/MgDev/Desktop/MgDesktop/Services/FeatureService.cpp
   trunk/MgDev/Desktop/MgDesktop/Services/FeatureService.h
   trunk/MgDev/Desktop/MgDesktop/Services/ResourceService.cpp
   trunk/MgDev/Desktop/MgDesktop/Services/ResourceService.h
   trunk/MgDev/Desktop/Samples/SampleExtension/ModifyingMapsAndLayers.cs
   trunk/MgDev/Desktop/UnitTest/TestFeatureService.cpp
   trunk/MgDev/Server/src/Services/Feature/FeatureOperationFactory.cpp
   trunk/MgDev/Server/src/Services/Feature/OpSelectFeatures.cpp
   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/Feature/ServerFeatureUtil.cpp
   trunk/MgDev/Server/src/Services/Feature/ServerFeatureUtil.h
   trunk/MgDev/Server/src/UnitTesting/TestFeatureService.cpp
   trunk/MgDev/Server/src/UnitTesting/TestFeatureService.h
   trunk/MgDev/Server/src/UnitTesting/TestMappingService.cpp
   trunk/MgDev/Server/src/UnitTesting/TestMappingService.h
   trunk/MgDev/UnitTest/WebTier/DotNet/MgTestRunner/Program.cs
   trunk/MgDev/UnitTest/WebTier/DotNet/TestCommon/CommonTests.cs
   trunk/MgDev/UnitTest/WebTier/DotNet/TestCommon/ExternalTests/CollectionTests.cs
   trunk/MgDev/UnitTest/WebTier/DotNet/TestCommon/ExternalTests/PropertiesTest.cs
   trunk/MgDev/UnitTest/WebTier/DotNet/TestCommon/TestCommon.csproj
   trunk/MgDev/UnitTest/WebTier/DotNet/TestMapGuideApi/ExternalTests/CollectionTests.cs
   trunk/MgDev/UnitTest/WebTier/DotNet/TestMapGuideApi/TestMapGuideApi.csproj
   trunk/MgDev/Web/src/DotNetUnmanagedApi/PlatformBase/PlatformBaseConstants.xml
   trunk/MgDev/Web/src/MapGuideApi/Constants.xml
Log:
Implement RFC 143 - Convenience APIs

This introduces the following new public APIs to MgFeatureService for simplified CRUD operations:

 * MgFeatureReader* InsertFeatures(MgResourceIdentifier* resource, CREFSTRING className, MgPropertyCollection* propertyValues)
 * MgFeatureReader* InsertFeatures(MgResourceIdentifier* resource, CREFSTRING className, MgPropertyCollection* propertyValues, MgTransaction* trans)
 * MgFeatureReader* InsertFeatures(MgResourceIdentifier* resource, CREFSTRING className, MgBatchPropertyCollection* batchPropertyValues)
 * MgFeatureReader* InsertFeatures(MgResourceIdentifier* resource, CREFSTRING className, MgBatchPropertyCollection* batchPropertyValues, MgTransaction* trans)
 * UpdateMatchingFeatures(MgResourceIdentifier* resource, CREFSTRING className, MgPropertyCollection* properties, CREFSTRING filter)
 * UpdateMatchingFeatures(MgResourceIdentifier* resource, CREFSTRING className, MgPropertyCollection* properties, CREFSTRING filter, MgTransaction* trans)
 * DeleteFeatures(MgResourceIdentifier* resource, CREFSTRING className, CREFSTRING filter)
 * DeleteFeatures(MgResourceIdentifier* resource, CREFSTRING className, CREFSTRING filter, MgTransaction* trans)

This previously un-implemented API is now implemented in MgFeatureService:

 * MgFeatureReader* SelectFeatures(MgResourceIdentifier* resource, CREFSTRING className, MgFeatureQueryOptions* options, CREFSTRING coordinateSystem)

This also introduces new public convenience APIs for MgLayerBase:

 * MgTransaction* BeginTransaction()
 * MgPropertyCollection* UpdateFeatures(MgFeatureCommandCollection* commands, MgTransaction* transaction)
 * MgFeatureReader* InsertFeatures(MgPropertyCollection* properties, MgTransaction* transaction)
 * MgFeatureReader* InsertFeatures(MgBatchPropertyCollection* properties, MgTransaction* transaction)
 * INT32 UpdateMatchingFeatures(MgPropertyCollection* properties, CREFSTRING filter, MgTransaction* transaction)
 * INT32 DeleteFeatures(CREFSTRING filter, MgTransaction* transaction)
 * MgSpatialContextReader* GetSpatialContexts(bool bActiveOnly)
 * MgFeatureReader* SelectFeatures(MgFeatureQueryOptions* options, CREFSTRING coordinateSystem)

This also introduces new public convenience APIs for MgLayer to simplify legend icon rendering code:

 * MgIntCollection* GetGeometryTypeStyles()
 * INT32 GetThemeCategoryCount(INT32 geomType)
 * INT32 GetCompositeThemeCategoryCount(INT32 compositeOffset)
 * MgByteReader* GenerateLegendImage(INT32 width, INT32 height, CREFSTRING format, INT32 geomType, INT32 themeCategory)
 * MgIntCollection* GetGeometryTypeStyles(double scale)
 * INT32 GetThemeCategoryCount(double scale, INT32 geomType)
 * INT32 GetCompositeThemeCategoryCount(double scale, INT32 compositeOffset)
 * MgByteReader* GenerateLegendImage(double scale, INT32 width, INT32 height, CREFSTRING format, INT32 geomType, INT32 themeCategory)

Finally, these APIs have been promoted to EXTERNAL_API from INTERNAL_API in MgResourceService:

 * MgDateTime* GetResourceModifiedDate(MgResourceIdentifier* resource)
 * STRING EnumerateResourceDocuments(MgStringCollection* resources, CREFSTRING type, INT32 properties)

The server test suite has been expanded to cover these new APIs and the .net test runner includes new external tests for these convenience APIs.


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
/sandbox/jng/convenience_apis:8263
/sandbox/jng/createruntimemap:7486-7555
/sandbox/jng/dwftk:8321-8324,8328-8329,8331,8352
/sandbox/jng/geos34x:8256-8259
/sandbox/jng/tiling:8174-8208
/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
/sandbox/jng/convenience_apis:8262-8268,8271-8363
/sandbox/jng/createruntimemap:7486-7555
/sandbox/jng/dwftk:8321-8324,8328-8329,8331,8352
/sandbox/jng/geos34x:8256-8259
/sandbox/jng/tiling:8174-8208
/sandbox/jng/v30:8212-8227
/sandbox/rfc94:5099-5163

Modified: trunk/MgDev/Common/MapGuideCommon/MapLayer/Layer.cpp
===================================================================
--- trunk/MgDev/Common/MapGuideCommon/MapLayer/Layer.cpp	2014-10-07 09:31:27 UTC (rev 8393)
+++ trunk/MgDev/Common/MapGuideCommon/MapLayer/Layer.cpp	2014-10-08 01:36:51 UTC (rev 8394)
@@ -17,6 +17,11 @@
 
 #include "MapGuideCommon.h"
 #include "FSDSAX2Parser.h"
+#include "AreaTypeStyle.h"
+#include "LineTypeStyle.h"
+#include "PointTypeStyle.h"
+#include "CompositeTypeStyle.h"
+#include <set>
 
 MG_IMPL_DYNCREATE(MgLayer)
 
@@ -280,6 +285,23 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 /// \brief
+/// Selects features from a feature source according to the
+/// criteria set in the MgFeatureQueryOptions argument The
+/// criteria are applied to all of the features in the feature
+/// source. If you want to apply the criteria to a subset of the
+/// features, use the MgFeatureService::SelectAggregate Method.
+///
+MgFeatureReader* MgLayer::SelectFeatures(MgFeatureQueryOptions* options, CREFSTRING coordinateSystem)
+{
+    Ptr<MgFeatureService> featureService = dynamic_cast<MgFeatureService*>(
+        GetMap()->GetService(MgServiceType::FeatureService));
+    Ptr<MgResourceIdentifier> resourceId = new MgResourceIdentifier(m_featureSourceId);
+
+    return featureService->SelectFeatures(resourceId, m_featureName, options, coordinateSystem);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/// \brief
 /// Selects groups of features from a feature source and applies
 /// filters to each of the groups according to the criteria set
 /// in the MgFeatureAggregateOptions argument. If you want to
@@ -307,6 +329,23 @@
 
     MG_TRY()
 
+    Ptr<MgResourceIdentifier> resourceId = new MgResourceIdentifier(m_featureSourceId);
+    STRING providerName = GetProviderName();
+    // Determine if the provider supports transactions.
+    Ptr<MgFeatureService> featureService = dynamic_cast<MgFeatureService*>(
+        GetMap()->GetService(MgServiceType::FeatureService));
+
+    bool useTransaction = UseTransaction(featureService, providerName);
+
+    propCol = featureService->UpdateFeatures(resourceId, commands, useTransaction);
+
+    MG_CATCH_AND_THROW(L"MgLayer.UpdateFeatures")
+
+    return propCol.Detach();
+}
+
+STRING MgLayer::GetProviderName()
+{
     // Get the content of the feature source.
     Ptr<MgResourceService> resourceService = dynamic_cast<MgResourceService*>(
         GetMap()->GetService(MgServiceType::ResourceService));
@@ -332,15 +371,14 @@
     featureSource.reset(parser.DetachFeatureSource());
 
     // Get the provider name.
-    STRING providerName = (STRING)featureSource->GetProvider();
+    return (STRING)featureSource->GetProvider();
+}
 
-    // Determine if the provider supports transactions.
+bool MgLayer::UseTransaction(MgFeatureService* featureService, CREFSTRING providerName)
+{
     bool useTransaction = false;
-    Ptr<MgFeatureService> featureService = dynamic_cast<MgFeatureService*>(
-        GetMap()->GetService(MgServiceType::FeatureService));
-
-    byteReader = featureService->GetCapabilities(providerName);
-    xmlContent.clear();
+    Ptr<MgByteReader> byteReader = featureService->GetCapabilities(providerName);
+    std::string xmlContent;
     byteReader->ToStringUtf8(xmlContent);
 
     const string openTag = "<SupportsTransactions>"; //NOXLATE
@@ -363,12 +401,7 @@
             useTransaction = MgUtil::StringToBoolean(tagValue);
         }
     }
-
-    propCol = featureService->UpdateFeatures(resourceId, commands, useTransaction);
-
-    MG_CATCH_AND_THROW(L"MgLayer.UpdateFeatures")
-
-    return propCol.Detach();
+    return useTransaction;
 }
 
 void MgLayer::ParseFeatureName(MgFeatureService* featureService, REFSTRING className, REFSTRING schemaName)
@@ -423,3 +456,327 @@
         m_idProps.push_back(idProp);
     }
 }
+
+MgTransaction* MgLayer::BeginTransaction()
+{
+    Ptr<MgTransaction> ret;
+
+    MG_TRY()
+
+    Ptr<MgResourceIdentifier> resourceId = new MgResourceIdentifier(m_featureSourceId);
+    Ptr<MgFeatureService> featureService = dynamic_cast<MgFeatureService*>(
+        GetMap()->GetService(MgServiceType::FeatureService));
+
+    ret = featureService->BeginTransaction(resourceId);
+
+    MG_CATCH_AND_THROW(L"MgLayer.BeginTransaction")
+
+    return ret.Detach();
+}
+
+MgPropertyCollection* MgLayer::UpdateFeatures(MgFeatureCommandCollection* commands, MgTransaction* transaction)
+{
+    Ptr<MgPropertyCollection> propCol;
+
+    MG_TRY()
+
+    Ptr<MgResourceIdentifier> resourceId = new MgResourceIdentifier(m_featureSourceId);
+    // Determine if the provider supports transactions.
+    Ptr<MgFeatureService> featureService = dynamic_cast<MgFeatureService*>(
+        GetMap()->GetService(MgServiceType::FeatureService));
+
+    propCol = featureService->UpdateFeatures(resourceId, commands, transaction);
+
+    MG_CATCH_AND_THROW(L"MgLayer.UpdateFeatures")
+
+    return propCol.Detach();
+}
+
+MgFeatureReader* MgLayer::InsertFeatures(MgPropertyCollection* properties, MgTransaction* transaction)
+{
+    Ptr<MgFeatureService> featureService = dynamic_cast<MgFeatureService*>(
+        GetMap()->GetService(MgServiceType::FeatureService));
+    Ptr<MgResourceIdentifier> resourceId = new MgResourceIdentifier(m_featureSourceId);
+
+    Ptr<MgFeatureReader> ret;
+    MG_TRY()
+
+    ret = featureService->InsertFeatures(resourceId, m_featureName, properties, transaction);
+
+    MG_CATCH_AND_THROW(L"MgLayer.InsertFeatures")
+
+    return ret.Detach();
+}
+
+MgFeatureReader* MgLayer::InsertFeatures(MgBatchPropertyCollection* properties, MgTransaction* transaction)
+{
+    Ptr<MgFeatureService> featureService = dynamic_cast<MgFeatureService*>(
+        GetMap()->GetService(MgServiceType::FeatureService));
+    Ptr<MgResourceIdentifier> resourceId = new MgResourceIdentifier(m_featureSourceId);
+
+    Ptr<MgFeatureReader> ret;
+    MG_TRY()
+
+    ret = featureService->InsertFeatures(resourceId, m_featureName, properties, transaction);
+
+    MG_CATCH_AND_THROW(L"MgLayer.InsertFeatures")
+
+    return ret.Detach();
+}
+
+INT32 MgLayer::UpdateMatchingFeatures(MgPropertyCollection* properties, CREFSTRING filter, MgTransaction* transaction)
+{
+    Ptr<MgFeatureService> featureService = dynamic_cast<MgFeatureService*>(
+        GetMap()->GetService(MgServiceType::FeatureService));
+    Ptr<MgResourceIdentifier> resourceId = new MgResourceIdentifier(m_featureSourceId);
+
+    INT32 updated = -1;
+    MG_TRY()
+
+    updated = featureService->UpdateMatchingFeatures(resourceId, m_featureName, properties, filter, transaction);
+    
+    MG_CATCH_AND_THROW(L"MgLayer.UpdateMatchingFeatures")
+
+    return updated;
+}
+
+INT32 MgLayer::DeleteFeatures(CREFSTRING filter, MgTransaction* transaction)
+{
+    Ptr<MgFeatureService> featureService = dynamic_cast<MgFeatureService*>(
+        GetMap()->GetService(MgServiceType::FeatureService));
+    Ptr<MgResourceIdentifier> resourceId = new MgResourceIdentifier(m_featureSourceId);
+
+    INT32 deleted = -1;
+    MG_TRY()
+
+    deleted = featureService->DeleteFeatures(resourceId, m_featureName, filter, transaction);
+
+    MG_CATCH_AND_THROW(L"MgLayer.DeleteFeatures")
+
+    return deleted;
+}
+
+MgIntCollection* MgLayer::GetGeometryTypeStyles()
+{
+    Ptr<MgIntCollection> ret;
+
+    MG_TRY()
+
+    ret = GetGeometryTypeStyles(GetMap()->GetViewScale());
+
+    MG_CATCH_AND_THROW(L"MgLayer.GetGeometryTypeStyles");
+
+    return ret.Detach();
+}
+
+INT32 MgLayer::GetThemeCategoryCount(INT32 geomType)
+{
+    return GetThemeCategoryCount(GetMap()->GetViewScale(), geomType);
+}
+
+MgByteReader* MgLayer::GenerateLegendImage(INT32 width, INT32 height, CREFSTRING format, INT32 geomType, INT32 themeCategory)
+{
+    Ptr<MgByteReader> ret;
+
+    MG_TRY()
+
+    ret = GenerateLegendImage(GetMap()->GetViewScale(), width, height, format, geomType, themeCategory);
+
+    MG_CATCH_AND_THROW(L"MgLayer.GenerateLegendImage");
+
+    return ret.Detach();
+}
+
+MgIntCollection* MgLayer::GetGeometryTypeStyles(double scale)
+{
+    Ptr<MgIntCollection> ret;
+
+    MG_TRY()
+
+    Ptr<MgResourceService> resSvc = dynamic_cast<MgResourceService*>(GetMap()->GetService(MgServiceType::ResourceService));
+    std::auto_ptr<MdfModel::LayerDefinition> ldf(MgLayerBase::GetLayerDefinition(resSvc, m_definition));
+    if (ldf.get() != NULL)
+    {
+        MdfModel::VectorLayerDefinition* vl = dynamic_cast<MdfModel::VectorLayerDefinition*>(ldf.get());
+        if(vl != NULL)
+        {
+            MdfModel::VectorScaleRangeCollection* scaleRanges = vl->GetScaleRanges();
+            if (scaleRanges != NULL)
+            {
+                for (INT32 i = 0; i < scaleRanges->GetCount(); i++)
+                {
+                    MdfModel::VectorScaleRange* vsr = scaleRanges->GetAt(i);
+                    if (scale >= vsr->GetMinScale() && scale < vsr->GetMaxScale())
+                    {
+                        MdfModel::FeatureTypeStyleCollection* ftsc = vsr->GetFeatureTypeStyles();
+
+                        ret = new MgIntCollection();
+
+                        for (INT32 j = 0; j < ftsc->GetCount(); j++)
+                        {
+                            MdfModel::PointTypeStyle* pts = dynamic_cast<MdfModel::PointTypeStyle*>(ftsc->GetAt(j));
+                            MdfModel::LineTypeStyle* lts = dynamic_cast<MdfModel::LineTypeStyle*>(ftsc->GetAt(j));
+                            MdfModel::AreaTypeStyle* ats = dynamic_cast<MdfModel::AreaTypeStyle*>(ftsc->GetAt(j));
+                            MdfModel::CompositeTypeStyle* cts = dynamic_cast<MdfModel::CompositeTypeStyle*>(ftsc->GetAt(j));
+
+                            if (pts != NULL)
+                            {
+                                if (ret->IndexOf(1) < 0)
+                                    ret->Add(1);
+                            }
+                            else if (lts != NULL)
+                            {
+                                if (ret->IndexOf(2) < 0)
+                                    ret->Add(2);
+                            }
+                            else if (ats != NULL)
+                            {
+                                if (ret->IndexOf(3) < 0)
+                                    ret->Add(3);
+                            }
+                            else if (cts != NULL)
+                            {
+                                ret->Add(4);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    MG_CATCH_AND_THROW(L"MgLayer.GenerateLegendImage");
+
+    return ret.Detach();
+}
+
+INT32 MgLayer::GetThemeCategoryCount(double scale, INT32 geomType)
+{
+    INT32 ret = -1;
+
+    Ptr<MgResourceService> resSvc = dynamic_cast<MgResourceService*>(GetMap()->GetService(MgServiceType::ResourceService));
+    std::auto_ptr<MdfModel::LayerDefinition> ldf(MgLayerBase::GetLayerDefinition(resSvc, m_definition));
+    if (ldf.get() != NULL)
+    {
+        MdfModel::VectorLayerDefinition* vl = dynamic_cast<MdfModel::VectorLayerDefinition*>(ldf.get());
+        if(vl != NULL)
+        {
+            MdfModel::VectorScaleRangeCollection* scaleRanges = vl->GetScaleRanges();
+            if (scaleRanges != NULL)
+            {
+                for (INT32 i = 0; i < scaleRanges->GetCount(); i++)
+                {
+                    MdfModel::VectorScaleRange* vsr = scaleRanges->GetAt(i);
+                    if (scale >= vsr->GetMinScale() && scale < vsr->GetMaxScale())
+                    {
+                        MdfModel::FeatureTypeStyleCollection* ftsc = vsr->GetFeatureTypeStyles();
+                        for (INT32 j = 0; j < ftsc->GetCount(); j++)
+                        {
+                            MdfModel::PointTypeStyle* pts = dynamic_cast<MdfModel::PointTypeStyle*>(ftsc->GetAt(j));
+                            MdfModel::LineTypeStyle* lts = dynamic_cast<MdfModel::LineTypeStyle*>(ftsc->GetAt(j));
+                            MdfModel::AreaTypeStyle* ats = dynamic_cast<MdfModel::AreaTypeStyle*>(ftsc->GetAt(j));
+                            MdfModel::CompositeTypeStyle* cts = dynamic_cast<MdfModel::CompositeTypeStyle*>(ftsc->GetAt(j));
+
+                            if (pts != NULL && geomType == 1)
+                            {
+                                ret = pts->GetRules()->GetCount();
+                                break;
+                            }
+                            else if (lts != NULL && geomType == 2)
+                            {
+                                ret = lts->GetRules()->GetCount();
+                                break;
+                            }
+                            else if (ats != NULL && geomType == 3)
+                            {
+                                ret = ats->GetRules()->GetCount();
+                                break;
+                            }
+                            else if (cts != NULL && geomType == 4)
+                            {
+                                ret = cts->GetRules()->GetCount();
+                                break;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+    
+    return ret;
+}
+
+INT32 MgLayer::GetCompositeThemeCategoryCount(INT32 compositeOffset)
+{
+    return GetCompositeThemeCategoryCount(GetMap()->GetViewScale(), compositeOffset);
+}
+
+INT32 MgLayer::GetCompositeThemeCategoryCount(double scale, INT32 compositeOffset)
+{
+    INT32 ret = -1;
+
+    Ptr<MgResourceService> resSvc = dynamic_cast<MgResourceService*>(GetMap()->GetService(MgServiceType::ResourceService));
+    std::auto_ptr<MdfModel::LayerDefinition> ldf(MgLayerBase::GetLayerDefinition(resSvc, m_definition));
+    if (ldf.get() != NULL)
+    {
+        MdfModel::VectorLayerDefinition* vl = dynamic_cast<MdfModel::VectorLayerDefinition*>(ldf.get());
+        if(vl != NULL)
+        {
+            MdfModel::VectorScaleRangeCollection* scaleRanges = vl->GetScaleRanges();
+            if (scaleRanges != NULL)
+            {
+                for (INT32 i = 0; i < scaleRanges->GetCount(); i++)
+                {
+                    MdfModel::VectorScaleRange* vsr = scaleRanges->GetAt(i);
+                    if (scale >= vsr->GetMinScale() && scale < vsr->GetMaxScale())
+                    {
+                        MdfModel::FeatureTypeStyleCollection* ftsc = vsr->GetFeatureTypeStyles();
+                        //NOTE: If a Layer Definition has basic and composite types, then this offset will probably be wrong
+                        //but such layers are technically illegal and we shouldn't try to be catering to such layers
+                        if (compositeOffset < ftsc->GetCount())
+                        {
+                            MdfModel::CompositeTypeStyle* cts = dynamic_cast<MdfModel::CompositeTypeStyle*>(ftsc->GetAt(compositeOffset));
+                            if (cts != NULL)
+                            {
+                                ret = cts->GetRules()->GetCount();
+                                break;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+    
+    return ret;
+}
+
+MgByteReader* MgLayer::GenerateLegendImage(double scale, INT32 width, INT32 height, CREFSTRING format, INT32 geomType, INT32 themeCategory)
+{
+    Ptr<MgByteReader> ret;
+
+    MG_TRY()
+
+    Ptr<MgMappingService> svcMapping = dynamic_cast<MgMappingService*>(GetMap()->GetService(MgServiceType::MappingService));
+    ret = svcMapping->GenerateLegendImage(m_definition, scale, width, height, format, geomType, themeCategory);
+
+    MG_CATCH_AND_THROW(L"MgLayer.GenerateLegendImage");
+
+    return ret.Detach();
+}
+
+MgSpatialContextReader* MgLayer::GetSpatialContexts(bool bActiveOnly)
+{
+    Ptr<MgSpatialContextReader> ret;
+
+    MG_TRY()
+
+    Ptr<MgFeatureService> svcFeature = dynamic_cast<MgFeatureService*>(GetMap()->GetService(MgServiceType::FeatureService));
+    Ptr<MgResourceIdentifier> fsId = new MgResourceIdentifier(m_featureSourceId);
+    ret = svcFeature->GetSpatialContexts(fsId, bActiveOnly);
+
+    MG_CATCH_AND_THROW(L"MgLayer.GetSpatialContexts");
+
+    return ret.Detach();
+}
\ No newline at end of file

Modified: trunk/MgDev/Common/MapGuideCommon/MapLayer/Layer.h
===================================================================
--- trunk/MgDev/Common/MapGuideCommon/MapLayer/Layer.h	2014-10-07 09:31:27 UTC (rev 8393)
+++ trunk/MgDev/Common/MapGuideCommon/MapLayer/Layer.h	2014-10-08 01:36:51 UTC (rev 8394)
@@ -131,6 +131,44 @@
 
     //////////////////////////////////////////////////////////////////
     /// \brief
+    /// Selects features from a feature source according to the
+    /// criteria set in the MgFeatureQueryOptions argument The
+    /// criteria are applied to all of the features in the feature
+    /// source. If you want to apply the criteria to a subset of the
+    /// features, use the \link MgFeatureService::SelectAggregate MgFeatureService::SelectAggregate Method \endlink.
+    /// See \link FiltersAndExpressions Filters and expressions \endlink.
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual MgFeatureReader SelectFeatures(MgFeatureQueryOptions options);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual MgFeatureReader SelectFeatures(MgFeatureQueryOptions options);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual MgFeatureReader SelectFeatures(MgFeatureQueryOptions options);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param options (MgFeatureQueryOptions)
+    /// MgFeatureQueryOptions instance
+    /// containing all required filters for this
+    /// select operation.
+    /// \param coordinateSystem (String/string)
+    /// The WKT string of the coordinate system to transform features to
+    ///
+    /// \return
+    /// Returns an MgFeatureReader containing the set of selected
+    /// features.
+    ///
+    /// \exception MgFeatureServiceException
+    /// \exception MgInvalidArgumentException
+    /// \exception MgFdoException
+    ///
+    /// \since 3.0
+    virtual MgFeatureReader* SelectFeatures(MgFeatureQueryOptions* options, CREFSTRING coordinateSystem);
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
     /// Selects groups of features from a feature source and applies
     /// filters to each of the groups according to the criteria set
     /// in the MgFeatureAggregateOptions argument. If you want to
@@ -224,6 +262,538 @@
     ///
     virtual MgPropertyCollection* UpdateFeatures(MgFeatureCommandCollection* commands);
 
+    ////////////////////////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Starts a transaction on the this layer. The FDO provider indicated by the layer's 
+    /// Feature Source must support transactions.
+    ///
+    /// \remarks
+    /// The XML returned by MgFeatureService::GetCapabilities says
+    /// whether a provider supports transactions. See \link ProviderCapabilities Provider Capabilities \endlink.
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual MgTransaction BeginTransaction();
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual MgTransaction BeginTransaction();
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual MgTransaction BeginTransaction();
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \return
+    /// Returns an MgTransaction instance (or NULL).
+    ///
+    /// \exception MgFeatureServiceException
+    /// \exception MgInvalidArgumentException
+    /// \exception MgInvalidOperationException
+    /// \exception MgFdoException
+    ///
+    /// \since 3.0
+    virtual MgTransaction* BeginTransaction();
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Executes the MgDeleteFeatures, MgInsertFeatures,
+    /// MgUpdateFeatures, MgLockFeatures or MgUnlockFeatures commands
+    /// contained in the given MgFeatureCommandCollection object.
+    ///
+    /// \remarks
+    /// The XML returned by MgFeatureService::GetCapabilities says
+    /// whether a provider supports SQL commands. See \link ProviderCapabilities Provider Capabilities \endlink.
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual MgPropertyCollection UpdateFeatures(MgFeatureCommandCollection commands);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual MgPropertyCollection UpdateFeatures(MgFeatureCommandCollection commands);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual MgPropertyCollection UpdateFeatures(MgFeatureCommandCollection commands);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param commands (MgFeatureCommandCollection)
+    /// A collection of feature commands to be
+    /// executed.
+    /// \param transaction (MgTransaction)
+    /// An optional transaction to execute this operation under
+    ///
+    /// \return
+    /// Returns an MgPropertyCollection object. Each property in the
+    /// collection corresponds to a command in the
+    /// MgFeatureCommandCollection argument. The property name is the
+    /// index of the command in the feature command collection.
+    /// <ul>
+    ///   <li>If the command is of type MgDeleteFeatures, the property
+    ///     type is an MgPropertyType::Int32, and its value is the number
+    ///     of features deleted.</li>
+    ///   <li>If the command is of type MgInsertFeatures, the property
+    ///     type is an MgPropertyType::Feature, and its value is a
+    ///     MgFeatureReader object. The feature reader object contains
+    ///     the set of properties inserted into the datastore by the
+    ///     insert command.</li>
+    ///   <li>If the command is of type MgUpdateFeatures, the property
+    ///     type is MgPropertyType::Int32, and its value is the number of
+    ///     features updated.</li>
+    ///   <li>If the command is of type MgLockFeatures, the property
+    ///     type is MgPropertyType::Feature, and its value is the number
+    ///     of features locked.</li>
+    ///   <li>If the command is of type MgUnLockFeatures, the property
+    ///     type is MgPropertyType::Int32, and its value is the number of
+    ///     features unlocked.</li>
+    /// </ul>
+    ///
+    /// \exception MgFeatureServiceException
+    /// \exception MgInvalidArgumentException
+    /// \exception MgInvalidOperationException
+    /// \exception MgFdoException
+    ///
+    /// \since 3.0
+    virtual MgPropertyCollection* UpdateFeatures(MgFeatureCommandCollection* commands, MgTransaction* transaction);
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Inserts a new feature into the specified feature class of the specified Feature Source
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual MgFeatureReader InsertFeatures(MgPropertyCollection properties);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual MgFeatureReader InsertFeatures(MgPropertyCollection properties);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual MgFeatureReader InsertFeatures(MgPropertyCollection properties);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param properties (MgPropertyCollection)
+    /// The collection of property values to insert
+    /// \param transaction (MgTransaction)
+    /// An optional transaction to execute this operation under
+    ///
+    /// \return
+    /// Returns a feature reader object that contains the set of properties 
+    /// inserted into the datastore by the insert command.
+    ///
+    /// \remarks
+    /// Remember to close any feature readers returned by this method, even if you don't intend
+    /// to do anything with them
+    ///
+    /// \exception MgFeatureServiceException
+    /// \exception MgInvalidArgumentException
+    /// \exception MgInvalidOperationException
+    /// \exception MgFdoException
+    ///
+    /// \since 3.0
+    virtual MgFeatureReader* InsertFeatures(MgPropertyCollection* properties, MgTransaction* transaction);
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Inserts a set of new features into the specified feature class of the specified Feature Source
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual MgFeatureReader InsertFeatures(MgBatchPropertyCollection properties);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual MgFeatureReader InsertFeatures(MgBatchPropertyCollection properties);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual MgFeatureReader InsertFeatures(MgBatchPropertyCollection properties);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param properties (MgBatchPropertyCollection)
+    /// The collection of property values to insert. Each MgPropertyCollection within 
+    /// this collection represents property values for a single feature to insert
+    /// \param transaction (MgTransaction)
+    /// An optional transaction to execute this operation under
+    ///
+    /// \return
+    /// Returns a feature reader object that contains the set of properties 
+    /// inserted into the datastore by the insert command.
+    ///
+    /// \remarks
+    /// Remember to close any feature readers returned by this method, even if you don't intend
+    /// to do anything with them
+    ///
+    /// \exception MgFeatureServiceException
+    /// \exception MgInvalidArgumentException
+    /// \exception MgInvalidOperationException
+    /// \exception MgFdoException
+    ///
+    /// \since 3.0
+    virtual MgFeatureReader* InsertFeatures(MgBatchPropertyCollection* properties, MgTransaction* transaction);
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Updates all features that match the given filter with the specified property values
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual int UpdateMatchingFeatures(MgPropertyCollection properties, string filter);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual int UpdateMatchingFeatures(MgPropertyCollection properties, String filter);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual int UpdateMatchingFeatures(MgPropertyCollection properties, String filter);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param properties (MgBatchPropertyCollection)
+    /// The property values to update matching features with
+    /// \param filter (String/string)
+    /// The FDO filter string that detemines what features will be updated
+    /// \param transaction (MgTransaction)
+    /// An optional transaction to execute this operation under
+    ///
+    /// \return
+    /// Returns the number of features updated by this operation
+    ///
+    /// \exception MgFeatureServiceException
+    /// \exception MgInvalidArgumentException
+    /// \exception MgInvalidOperationException
+    /// \exception MgFdoException
+    ///
+    /// \since 3.0
+    virtual INT32 UpdateMatchingFeatures(MgPropertyCollection* properties, CREFSTRING filter, MgTransaction* transaction);
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Deletes all features that match the given filter
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual int DeleteFeatures(string filter);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual int DeleteFeatures(String filter);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual int DeleteFeatures(String filter);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param filter (String/string)
+    /// The FDO filter string that detemines what features will be deleted
+    /// \param transaction (MgTransaction)
+    /// An optional transaction to execute this operation under
+    ///
+    /// \return
+    /// Returns the number of features deleted by this operation
+    ///
+    /// \exception MgFeatureServiceException
+    /// \exception MgInvalidArgumentException
+    /// \exception MgInvalidOperationException
+    /// \exception MgFdoException
+    ///
+    /// \since 3.0
+    virtual INT32 DeleteFeatures(CREFSTRING filter, MgTransaction* transaction);
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Gets the list of geometry type styles for this layer at the map's current scale. Returns NULL if there are no applicable geometry types
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual MgIntCollection GetGeometryTypeStyles();
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual MgIntCollection GetGeometryTypeStyles();
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual MgIntCollection GetGeometryTypeStyles();
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \remarks
+    /// The map's current scale is used to determine what scale range in the layer definition to search for.
+    /// For a scale range with multiple composite styles, multiple instances of (4 = composite) will be in the resulting collection
+    ///
+    /// \return
+    /// The list of geometry type styles for this layer at the map's current scale. Returns NULL if there are no applicable geometry types
+    ///
+    /// \since 3.0
+    MgIntCollection* GetGeometryTypeStyles();
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Gets the number of theme categories for this layer at the map's current scale for the given geometry type style. A count greater than 1 indicates a themed layer. Returns -1 if there are no applicable styles at the current scale
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual int GetThemeCategoryCount(int geomType);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual int GetThemeCategoryCount(int geomType);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual int GetThemeCategoryCount(int geomType);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param geomType (int)
+    /// The geometry type
+    ///
+    /// \remarks
+    /// The map's current scale is used to determine what scale range in the layer definition to search for.
+    /// When geomType = 4, it will only count the number of the theme categories for the first composite style it finds. For a scale range
+    /// with multiple composite type styles, you should use GetCompositeThemeCategoryCount() instead
+    ///
+    /// \return
+    /// The number of theme categories for this layer at the map's current scale for the given geometry type style. A count greater than 1 indicates a themed layer. Returns -1 if there are no applicable styles at the current scale
+    ///
+    /// \since 3.0
+    INT32 GetThemeCategoryCount(INT32 geomType);
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Gets the number of composite theme categories for this layer at the map's current scale for the given composite style. A count greater than 1 indicates a themed layer. Returns -1 if there are no applicable styles at the current scale
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual int GetThemeCategoryCount(double scale, int geomType);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual int GetThemeCategoryCount(double scale, int geomType);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual int GetThemeCategoryCount(double scale, int geomType);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param compositeOffset (int)
+    /// The zero-based index denoting the particular composite style to count from. 0 = 1st composite style, 1 = 2nd composite style
+    ///
+    /// \return
+    /// The number of theme categories for this layer at the map's current scale for the given composite style. A count greater than 1 indicates a themed layer. Returns -1 if there are no applicable styles at the current scale
+    ///
+    /// \since 3.0
+    INT32 GetCompositeThemeCategoryCount(INT32 compositeOffset);
+
+    ////////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Returns the legend image for the specified geometry type and theme category
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual MgByteReader GenerateLegendImage(int width, int height, string format, int geomType, int themeCategory);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual MgByteReader GenerateLegendImage(int width, int height, String format, int geomType, int themeCategory);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual MgByteReader GenerateLegendImage(int width, int height, string format, int geomType, int themeCategory);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param resource (MgResourceIdentifier)
+    /// Input
+    /// MgResourceIdentifier object identifying the layer definition resource.
+    /// \param scale (double)
+    /// Input
+    /// The scale at which the symbolization is requested.
+    /// \param width (int)
+    /// Input
+    /// The requested image width in pixels.
+    /// \param height (int)
+    /// Input
+    /// The requested image height in pixels.
+    /// \param format (String/string)
+    /// Input
+    /// Image format, from MgImageFormats. Example: PNG, JPG, PNG8, etc 
+    /// \param geomType (int)
+    /// Input
+    /// The type of symbolization required: 1=Point, 2=Line, 3=Area, 4=Composite
+    /// \param themeCategory (int)
+    /// Input
+    /// The value indicating which theme category swatch to return.
+    /// Used when there is a theme defined at this scale. An exception will be
+    /// thrown if a requested them category doesn't exist.
+    ///
+    /// \remarks
+    /// The map's current scale is used to determine what scale range in the layer definition to search for
+    ///
+    /// \return
+    /// Returns a stream representing the legend image.
+    /// The default returned image format will be PNG8 unless a different supported
+    /// format is requested. An exception will be thrown if an unsupported image
+    /// format is requested.
+    ///
+    /// \exception MgArgumentOutOfRangeException
+    /// \exception MgInvalidResourceTypeException
+    /// \exception MgNullArgumentException
+    /// \exception MgInvalidImageFormatException
+    ///
+    /// \since 3.0
+    MgByteReader* GenerateLegendImage(INT32 width, INT32 height, CREFSTRING format, INT32 geomType, INT32 themeCategory);
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Gets the list of geometry type styles for this layer at the map's current scale. Returns NULL if there are no applicable geometry types
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual MgIntCollection GetGeometryTypeStyles(double scale);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual MgIntCollection GetGeometryTypeStyles(double scale);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual MgIntCollection GetGeometryTypeStyles(double scale);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param scale (double)
+    /// The scale at which to retrive the list of applicable geometry types
+    ///
+    /// \remarks
+    /// For a scale range with multiple composite styles, multiple instances of (4 = composite) will be in the resulting collection
+    ///
+    /// \return
+    /// The list of geometry type styles for this layer at the map's current scale. Returns NULL if there are no applicable geometry types
+    ///
+    /// \since 3.0
+    MgIntCollection* GetGeometryTypeStyles(double scale);
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Gets the number of theme categories for this layer at the map's current scale for the given geometry type style. A count greater than 1 indicates a themed layer. Returns -1 if there are no applicable styles at the current scale
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual int GetThemeCategoryCount(double scale, int geomType);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual int GetThemeCategoryCount(double scale, int geomType);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual int GetThemeCategoryCount(double scale, int geomType);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param scale (double)
+    /// The scale at which to count the number of applicable theme categories
+    /// \param geomType (int)
+    /// The geometry type
+    ///
+    /// \remarks
+    /// When geomType = 4, it will only count the number of the theme categories for the first composite style it finds. For a scale range
+    /// with multiple composite type styles, you should use GetCompositeThemeCategoryCount() instead
+    ///
+    /// \return
+    /// The number of theme categories for this layer at the map's current scale for the given geometry type style. A count greater than 1 indicates a themed layer. Returns -1 if there are no applicable styles at the current scale
+    ///
+    /// \since 3.0
+    INT32 GetThemeCategoryCount(double scale, INT32 geomType);
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Gets the number of composite theme categories for this layer at the map's current scale for the given composite style. A count greater than 1 indicates a themed layer. Returns -1 if there are no applicable styles at the current scale
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual int GetThemeCategoryCount(double scale, int geomType);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual int GetThemeCategoryCount(double scale, int geomType);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual int GetThemeCategoryCount(double scale, int geomType);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param scale (double)
+    /// The scale at which to count the number of applicable theme categories
+    /// \param compositeOffset (int)
+    /// The zero-based index denoting the particular composite style to count from. 0 = 1st composite style, 1 = 2nd composite style
+    ///
+    /// \return
+    /// The number of theme categories for this layer at the map's current scale for the given composite style. A count greater than 1 indicates a themed layer. Returns -1 if there are no applicable styles at the current scale
+    ///
+    /// \since 3.0
+    INT32 GetCompositeThemeCategoryCount(double scale, INT32 compositeOffset);
+
+    ////////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Returns the legend image for the specified geometry type and theme category
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual MgByteReader GenerateLegendImage(double scale, int width, int height, string format, int geomType, int themeCategory);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual MgByteReader GenerateLegendImage(double scale, int width, int height, String format, int geomType, int themeCategory);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual MgByteReader GenerateLegendImage(double scale, int width, int height, string format, int geomType, int themeCategory);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param resource (MgResourceIdentifier)
+    /// Input
+    /// MgResourceIdentifier object identifying the layer definition resource.
+    /// \param scale (double)
+    /// Input
+    /// The scale at which the symbolization is requested.
+    /// \param width (int)
+    /// Input
+    /// The requested image width in pixels.
+    /// \param height (int)
+    /// Input
+    /// The requested image height in pixels.
+    /// \param format (String/string)
+    /// Input
+    /// Image format, from MgImageFormats. Example: PNG, JPG, PNG8, etc 
+    /// \param geomType (int)
+    /// Input
+    /// The type of symbolization required: 1=Point, 2=Line, 3=Area, 4=Composite
+    /// \param themeCategory (int)
+    /// Input
+    /// The value indicating which theme category swatch to return.
+    /// Used when there is a theme defined at this scale. An exception will be
+    /// thrown if a requested them category doesn't exist.
+    ///
+    /// \return
+    /// Returns a stream representing the legend image.
+    /// The default returned image format will be PNG8 unless a different supported
+    /// format is requested. An exception will be thrown if an unsupported image
+    /// format is requested.
+    ///
+    /// \exception MgArgumentOutOfRangeException
+    /// \exception MgInvalidResourceTypeException
+    /// \exception MgNullArgumentException
+    /// \exception MgInvalidImageFormatException
+    ///
+    /// \since 3.0
+    MgByteReader* GenerateLegendImage(double scale, INT32 width, INT32 height, CREFSTRING format, INT32 geomType, INT32 themeCategory);
+
+    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Gets all of the spatial contexts available in the layer or just the active one
+    ///
+    /// \remarks
+    /// The \link FdoSpatialContextList_schema FdoSpatialContextList \endlink XML schema contains
+    /// a specification of the content of the spatial context
+    /// information returned in the MgSpatialContextReader object.
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual MgSpatialContextReader GetSpatialContexts(bool bActiveOnly);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual MgSpatialContextReader GetSpatialContexts(boolean bActiveOnly);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual MgSpatialContextReader GetSpatialContexts(bool bActiveOnly);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param bActiveOnly (boolean/bool)
+    /// This flag is obsolete and no longer used.
+    ///
+    /// \return
+    /// Returns an MgSpatialContextReader object.
+    ///
+    /// \exception MgFeatureServiceException
+    /// \exception MgInvalidArgumentException
+    /// \exception MgInvalidOperationException
+    /// \exception MgFdoException
+    ///
+    /// \since 3.0
+    virtual MgSpatialContextReader* GetSpatialContexts(bool bActiveOnly);
+
 INTERNAL_API:
 
     //////////////////////////////////////////////////////////////////
@@ -308,6 +878,8 @@
     }
 
 private:
+    STRING GetProviderName();
+    bool UseTransaction(MgFeatureService* svcFeature, CREFSTRING providerName);
 
     MgMapBase* GetMap();
 

Modified: trunk/MgDev/Common/MapGuideCommon/Services/ProxyFeatureService.cpp
===================================================================
--- trunk/MgDev/Common/MapGuideCommon/Services/ProxyFeatureService.cpp	2014-10-07 09:31:27 UTC (rev 8393)
+++ trunk/MgDev/Common/MapGuideCommon/Services/ProxyFeatureService.cpp	2014-10-08 01:36:51 UTC (rev 8394)
@@ -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);
 }
 
 
@@ -1897,3 +1913,228 @@
     SetWarning(cmd.GetWarningObject());
     return cmd.GetReturnValue().val.m_i8;
 }
+
+MgFeatureReader* MgProxyFeatureService::InsertFeatures(MgResourceIdentifier* resource,
+                                                       CREFSTRING className,
+                                                       MgPropertyCollection* propertyValues)
+
+{
+    MgCommand cmd;
+    cmd.ExecuteCommand(m_connProp,                                  // Connection
+                       MgCommand::knObject,                         // Return type expected
+                       MgFeatureServiceOpId::InsertFeatures,        // Command Code
+                       3,                                           // 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, propertyValues,         // Argument#3
+                       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);
+}
+
+MgFeatureReader* MgProxyFeatureService::InsertFeatures(MgResourceIdentifier* resource,
+                                                       CREFSTRING className,
+                                                       MgPropertyCollection* propertyValues,
+                                                       MgTransaction* transaction)
+{
+    STRING transactionId = L"";
+    MgProxyFeatureTransaction* proxyTransaction = dynamic_cast<MgProxyFeatureTransaction*>(transaction);
+    if (NULL != proxyTransaction)
+    {
+        transactionId = proxyTransaction->GetTransactionId();
+    }
+
+    MgCommand cmd;
+    cmd.ExecuteCommand(m_connProp,                                  // Connection
+                       MgCommand::knObject,                         // Return type expected
+                       MgFeatureServiceOpId::InsertFeatures,        // 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, propertyValues,         // Argument#3
+                       MgCommand::knString, &transactionId,         // Argument#4
+                       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);
+}
+
+MgFeatureReader* MgProxyFeatureService::InsertFeatures(MgResourceIdentifier* resource,
+                                                       CREFSTRING className,
+                                                       MgBatchPropertyCollection* batchPropertyValues)
+{
+    MgCommand cmd;
+    cmd.ExecuteCommand(m_connProp,                                  // Connection
+                       MgCommand::knObject,                         // Return type expected
+                       MgFeatureServiceOpId::InsertFeatures2,       // Command Code
+                       3,                                           // 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, batchPropertyValues,    // Argument#3
+                       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);
+}
+
+MgFeatureReader* MgProxyFeatureService::InsertFeatures(MgResourceIdentifier* resource,
+                                                       CREFSTRING className,
+                                                       MgBatchPropertyCollection* batchPropertyValues,
+                                                       MgTransaction* transaction)
+{
+    STRING transactionId = L"";
+    MgProxyFeatureTransaction* proxyTransaction = dynamic_cast<MgProxyFeatureTransaction*>(transaction);
+    if (NULL != proxyTransaction)
+    {
+        transactionId = proxyTransaction->GetTransactionId();
+    }
+
+    MgCommand cmd;
+    cmd.ExecuteCommand(m_connProp,                                  // Connection
+                       MgCommand::knObject,                         // Return type expected
+                       MgFeatureServiceOpId::InsertFeatures2,       // 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, batchPropertyValues,    // Argument#3
+                       MgCommand::knString, &transactionId,         // Argument#4
+                       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);
+}
+
+INT32 MgProxyFeatureService::UpdateMatchingFeatures(MgResourceIdentifier* resource,
+                                                    CREFSTRING className,
+                                                    MgPropertyCollection* propertyValues,
+                                                    CREFSTRING filter)
+{
+    MgCommand cmd;
+    cmd.ExecuteCommand(m_connProp,                                  // Connection
+                       MgCommand::knInt32,                          // Return type expected
+                       MgFeatureServiceOpId::UpdateMatchingFeatures,// 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, propertyValues,         // Argument#3
+                       MgCommand::knString, &filter,                // Argument#4
+                       MgCommand::knNone);                          // End of argument
+
+    SetWarning(cmd.GetWarningObject());
+    return cmd.GetReturnValue().val.m_i32;
+}
+
+INT32 MgProxyFeatureService::UpdateMatchingFeatures(MgResourceIdentifier* resource,
+                                                    CREFSTRING className,
+                                                    MgPropertyCollection* propertyValues,
+                                                    CREFSTRING filter,
+                                                    MgTransaction* transaction)
+{
+    STRING transactionId = L"";
+    MgProxyFeatureTransaction* proxyTransaction = dynamic_cast<MgProxyFeatureTransaction*>(transaction);
+    if (NULL != proxyTransaction)
+    {
+        transactionId = proxyTransaction->GetTransactionId();
+    }
+
+    MgCommand cmd;
+    cmd.ExecuteCommand(m_connProp,                                  // Connection
+                       MgCommand::knInt32,                          // Return type expected
+                       MgFeatureServiceOpId::UpdateMatchingFeatures,// Command Code
+                       5,                                           // 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, propertyValues,         // Argument#3
+                       MgCommand::knString, &filter,                // Argument#4
+                       MgCommand::knString, &transactionId,         // Argument#5
+                       MgCommand::knNone);                          // End of argument
+
+    SetWarning(cmd.GetWarningObject());
+    return cmd.GetReturnValue().val.m_i32;
+}
+
+INT32 MgProxyFeatureService::DeleteFeatures(MgResourceIdentifier* resource,
+                                            CREFSTRING className,
+                                            CREFSTRING filter)
+{
+    MgCommand cmd;
+    cmd.ExecuteCommand(m_connProp,                                  // Connection
+                       MgCommand::knInt32,                          // Return type expected
+                       MgFeatureServiceOpId::DeleteFeatures,        // Command Code
+                       3,                                           // 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::knString, &filter,                // Argument#3
+                       MgCommand::knNone);                          // End of argument
+
+    SetWarning(cmd.GetWarningObject());
+    return cmd.GetReturnValue().val.m_i32;
+}
+
+INT32 MgProxyFeatureService::DeleteFeatures(MgResourceIdentifier* resource,
+                                            CREFSTRING className,
+                                            CREFSTRING filter,
+                                            MgTransaction* transaction)
+{
+    STRING transactionId = L"";
+    MgProxyFeatureTransaction* proxyTransaction = dynamic_cast<MgProxyFeatureTransaction*>(transaction);
+    if (NULL != proxyTransaction)
+    {
+        transactionId = proxyTransaction->GetTransactionId();
+    }
+
+    MgCommand cmd;
+    cmd.ExecuteCommand(m_connProp,                                  // Connection
+                       MgCommand::knInt32,                          // Return type expected
+                       MgFeatureServiceOpId::DeleteFeatures,        // 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::knString, &filter,                // Argument#3
+                       MgCommand::knString, &transactionId,         // Argument#4
+                       MgCommand::knNone);                          // End of argument
+
+    SetWarning(cmd.GetWarningObject());
+    return cmd.GetReturnValue().val.m_i32;
+}
\ No newline at end of file

Modified: trunk/MgDev/Common/MapGuideCommon/Services/ProxyFeatureService.h
===================================================================
--- trunk/MgDev/Common/MapGuideCommon/Services/ProxyFeatureService.h	2014-10-07 09:31:27 UTC (rev 8393)
+++ trunk/MgDev/Common/MapGuideCommon/Services/ProxyFeatureService.h	2014-10-08 01:36:51 UTC (rev 8394)
@@ -659,6 +659,342 @@
                                          MgFeatureCommandCollection* commands,
                                          MgTransaction* transaction);
 
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Inserts a new feature into the specified feature class of the specified Feature Source
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual MgFeatureReader InsertFeatures(MgResourceIdentifier resource, string className, MgPropertyCollection propertyValues);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual MgFeatureReader InsertFeatures(MgResourceIdentifier resource, String className, MgPropertyCollection propertyValues);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual MgFeatureReader InsertFeatures(MgResourceIdentifier resource, String className, MgPropertyCollection propertyValues);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param resource (MgResourceIdentifier)
+    /// A resource identifier for the feature
+    /// source.
+    /// \param className (String/string)
+    /// The name of the feature class on which
+    /// the insert operation is performed.
+    /// \param propertyValues (MgPropertyCollection)
+    /// The collection of property values to insert
+    ///
+    /// \return
+    /// Returns a feature reader object that contains the set of properties 
+    /// inserted into the datastore by the insert command.
+    ///
+    /// \remarks
+    /// Remember to close any feature readers returned by this method, even if you don't intend
+    /// to do anything with them
+    ///
+    /// \exception MgFeatureServiceException
+    /// \exception MgInvalidArgumentException
+    /// \exception MgInvalidOperationException
+    /// \exception MgFdoException
+    ///
+    /// \since 3.0
+    virtual MgFeatureReader* InsertFeatures(MgResourceIdentifier* resource,
+                                            CREFSTRING className,
+                                            MgPropertyCollection* propertyValues);
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Inserts a new feature into the specified feature class of the specified Feature Source
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual MgFeatureReader InsertFeatures(MgResourceIdentifier resource, string className, MgPropertyCollection propertyValues, MgTransaction trans);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual MgFeatureReader InsertFeatures(MgResourceIdentifier resource, String className, MgPropertyCollection propertyValues, MgTransaction trans);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual MgFeatureReader InsertFeatures(MgResourceIdentifier resource, String className, MgPropertyCollection propertyValues, MgTransaction trans);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param resource (MgResourceIdentifier)
+    /// A resource identifier for the feature
+    /// source.
+    /// \param className (String/string)
+    /// The name of the feature class on which
+    /// the insert operation is performed.
+    /// \param propertyValues (MgPropertyCollection)
+    /// The collection of property values to insert
+    /// \param trans (MgTransaction)
+    /// The transaction to execute this operation under
+    ///
+    /// \return
+    /// Returns a feature reader object that contains the set of properties 
+    /// inserted into the datastore by the insert command.
+    ///
+    /// \remarks
+    /// Remember to close any feature readers returned by this method, even if you don't intend
+    /// to do anything with them
+    ///
+    /// \exception MgFeatureServiceException
+    /// \exception MgInvalidArgumentException
+    /// \exception MgInvalidOperationException
+    /// \exception MgFdoException
+    ///
+    /// \since 3.0
+    virtual MgFeatureReader* InsertFeatures(MgResourceIdentifier* resource,
+                                            CREFSTRING className,
+                                            MgPropertyCollection* propertyValues,
+                                            MgTransaction* trans);
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Inserts a set of new features into the specified feature class of the specified Feature Source
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual MgFeatureReader InsertFeatures(MgResourceIdentifier resource, string className, MgBatchPropertyCollection batchPropertyValues);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual MgFeatureReader InsertFeatures(MgResourceIdentifier resource, String className, MgBatchPropertyCollection batchPropertyValues);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual MgFeatureReader InsertFeatures(MgResourceIdentifier resource, String className, MgBatchPropertyCollection batchPropertyValues);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param resource (MgResourceIdentifier)
+    /// A resource identifier for the feature
+    /// source.
+    /// \param className (String/string)
+    /// The name of the feature class on which
+    /// the insert operation is performed.
+    /// \param batchPropertyValues (MgBatchPropertyCollection)
+    /// The collection of property values to insert. Each MgPropertyCollection within 
+    /// this collection represents property values for a single feature to insert
+    ///
+    /// \return
+    /// Returns a feature reader object that contains the set of properties 
+    /// inserted into the datastore by the insert command.
+    ///
+    /// \remarks
+    /// Remember to close any feature readers returned by this method, even if you don't intend
+    /// to do anything with them
+    ///
+    /// \exception MgFeatureServiceException
+    /// \exception MgInvalidArgumentException
+    /// \exception MgInvalidOperationException
+    /// \exception MgFdoException
+    ///
+    /// \since 3.0
+    virtual MgFeatureReader* InsertFeatures(MgResourceIdentifier* resource,
+                                            CREFSTRING className,
+                                            MgBatchPropertyCollection* batchPropertyValues);
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Inserts a set of new features into the specified feature class of the specified Feature Source
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual MgFeatureReader InsertFeatures(MgResourceIdentifier resource, string className, MgBatchPropertyCollection batchPropertyValues, MgTransaction trans);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual MgFeatureReader InsertFeatures(MgResourceIdentifier resource, String className, MgBatchPropertyCollection batchPropertyValues, MgTransaction trans);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual MgFeatureReader InsertFeatures(MgResourceIdentifier resource, String className, MgBatchPropertyCollection batchPropertyValues, MgTransaction trans);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param resource (MgResourceIdentifier)
+    /// A resource identifier for the feature
+    /// source.
+    /// \param className (String/string)
+    /// The name of the feature class on which
+    /// the insert operation is performed.
+    /// \param batchPropertyValues (MgBatchPropertyCollection)
+    /// The collection of property values to insert. Each MgPropertyCollection within 
+    /// this collection represents property values for a single feature to insert
+    /// \param trans (MgTransaction)
+    /// The transaction to execute this operation under
+    ///
+    /// \return
+    /// Returns a feature reader object that contains the set of properties 
+    /// inserted into the datastore by the insert command.
+    ///
+    /// \remarks
+    /// Remember to close any feature readers returned by this method, even if you don't intend
+    /// to do anything with them
+    ///
+    /// \exception MgFeatureServiceException
+    /// \exception MgInvalidArgumentException
+    /// \exception MgInvalidOperationException
+    /// \exception MgFdoException
+    ///
+    /// \since 3.0
+    virtual MgFeatureReader* InsertFeatures(MgResourceIdentifier* resource,
+                                            CREFSTRING className,
+                                            MgBatchPropertyCollection* batchPropertyValues,
+                                            MgTransaction* trans);
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Updates all features that match the given filter with the specified property values
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual int UpdateMatchingFeatures(MgResourceIdentifier resource, string className, MgPropertyCollection properties, string filter);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual int UpdateMatchingFeatures(MgResourceIdentifier resource, String className, MgPropertyCollection properties, String filter);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual int UpdateMatchingFeatures(MgResourceIdentifier resource, String className, MgPropertyCollection properties, String filter);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param resource (MgResourceIdentifier)
+    /// A resource identifier for the feature
+    /// source.
+    /// \param className (String/string)
+    /// The name of the feature class on which
+    /// the update operation is performed.
+    /// \param properties (MgBatchPropertyCollection)
+    /// The property values to update matching features with
+    /// \param filter (String/string)
+    /// The FDO filter string that detemines what features will be updated
+    ///
+    /// \return
+    /// Returns the number of features updated by this operation
+    ///
+    /// \exception MgFeatureServiceException
+    /// \exception MgInvalidArgumentException
+    /// \exception MgInvalidOperationException
+    /// \exception MgFdoException
+    ///
+    /// \since 3.0
+    virtual INT32 UpdateMatchingFeatures(MgResourceIdentifier* resource,
+                                         CREFSTRING className,
+                                         MgPropertyCollection* properties,
+                                         CREFSTRING filter);
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Updates all features that match the given filter with the specified property values
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual int UpdateMatchingFeatures(MgResourceIdentifier resource, string className, MgPropertyCollection properties, string filter, MgTransaction trans);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual int UpdateMatchingFeatures(MgResourceIdentifier resource, String className, MgPropertyCollection properties, String filter, MgTransaction trans);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual int UpdateMatchingFeatures(MgResourceIdentifier resource, String className, MgPropertyCollection properties, String filter, MgTransaction trans);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param resource (MgResourceIdentifier)
+    /// A resource identifier for the feature
+    /// source.
+    /// \param className (String/string)
+    /// The name of the feature class on which
+    /// the update operation is performed.
+    /// \param properties (MgBatchPropertyCollection)
+    /// The property values to update matching features with
+    /// \param filter (String/string)
+    /// The FDO filter string that detemines what features will be updated
+    /// \param trans (MgTransaction)
+    /// The transaction to execute this operation under
+    ///
+    /// \return
+    /// Returns the number of features updated by this operation
+    ///
+    /// \exception MgFeatureServiceException
+    /// \exception MgInvalidArgumentException
+    /// \exception MgInvalidOperationException
+    /// \exception MgFdoException
+    ///
+    /// \since 3.0
+    virtual INT32 UpdateMatchingFeatures(MgResourceIdentifier* resource,
+                                         CREFSTRING className,
+                                         MgPropertyCollection* properties,
+                                         CREFSTRING filter,
+                                         MgTransaction* trans);
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Deletes all features that match the given filter
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual int DeleteFeatures(MgResourceIdentifier resource, string className, string filter);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual int DeleteFeatures(MgResourceIdentifier resource, String className, String filter);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual int DeleteFeatures(MgResourceIdentifier resource, String className, String filter);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param resource (MgResourceIdentifier)
+    /// A resource identifier for the feature
+    /// source.
+    /// \param className (String/string)
+    /// The name of the feature class on which
+    /// the delete operation is performed.
+    /// \param filter (String/string)
+    /// The FDO filter string that detemines what features will be deleted
+    ///
+    /// \return
+    /// Returns the number of features deleted by this operation
+    ///
+    /// \exception MgFeatureServiceException
+    /// \exception MgInvalidArgumentException
+    /// \exception MgInvalidOperationException
+    /// \exception MgFdoException
+    ///
+    /// \since 3.0
+    virtual INT32 DeleteFeatures(MgResourceIdentifier* resource,
+                                 CREFSTRING className,
+                                 CREFSTRING filter);
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Deletes all features that match the given filter
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual int DeleteFeatures(MgResourceIdentifier resource, string className, string filter, MgTransaction trans);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual int DeleteFeatures(MgResourceIdentifier resource, String className, String filter, MgTransaction trans);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual int DeleteFeatures(MgResourceIdentifier resource, String className, String filter, MgTransaction trans);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param resource (MgResourceIdentifier)
+    /// A resource identifier for the feature
+    /// source.
+    /// \param className (String/string)
+    /// The name of the feature class on which
+    /// the delete operation is performed.
+    /// \param filter (String/string)
+    /// The FDO filter string that detemines what features will be deleted
+    /// \param trans (MgTransaction)
+    /// The transaction to execute this operation under
+    ///
+    /// \return
+    /// Returns the number of features deleted by this operation
+    ///
+    /// \exception MgFeatureServiceException
+    /// \exception MgInvalidArgumentException
+    /// \exception MgInvalidOperationException
+    /// \exception MgFdoException
+    ///
+    /// \since 3.0
+    virtual INT32 DeleteFeatures(MgResourceIdentifier* resource,
+                                 CREFSTRING className,
+                                 CREFSTRING filter,
+                                 MgTransaction* trans);
+
     ////////////////////////////////////////////////////////////////////////////////////////////////
     /// \brief
     /// Gets the locked features

Modified: trunk/MgDev/Common/PlatformBase/MapLayer/LayerBase.cpp
===================================================================
--- trunk/MgDev/Common/PlatformBase/MapLayer/LayerBase.cpp	2014-10-07 09:31:27 UTC (rev 8393)
+++ trunk/MgDev/Common/PlatformBase/MapLayer/LayerBase.cpp	2014-10-08 01:36:51 UTC (rev 8394)
@@ -776,6 +776,20 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 /// \brief
+/// Selects features from a feature source according to the
+/// criteria set in the MgFeatureQueryOptions argument The
+/// criteria are applied to all of the features in the feature
+/// source. If you want to apply the criteria to a subset of the
+/// features, use the MgFeatureService::SelectAggregate Method.
+///
+MgFeatureReader* MgLayerBase::SelectFeatures(MgFeatureQueryOptions* options, CREFSTRING coordinateSystem)
+{
+    throw new MgNotImplementedException(L"MgLayerBase.SelectFeatures",
+        __LINE__, __WFILE__, NULL, L"", NULL);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/// \brief
 /// Selects groups of features from a feature source and applies
 /// filters to each of the groups according to the criteria set
 /// in the MgFeatureAggregateOptions argument. If you want to
@@ -799,3 +813,45 @@
     throw new MgNotImplementedException(L"MgLayerBase.UpdateFeatures",
         __LINE__, __WFILE__, NULL, L"", NULL);
 }
+
+MgPropertyCollection* MgLayerBase::UpdateFeatures(MgFeatureCommandCollection* commands, MgTransaction* transaction)
+{
+    throw new MgNotImplementedException(L"MgLayerBase.UpdateFeatures",
+        __LINE__, __WFILE__, NULL, L"", NULL);
+}
+
+MgTransaction* MgLayerBase::BeginTransaction()
+{
+    throw new MgNotImplementedException(L"MgLayerBase.BeginTransaction",
+        __LINE__, __WFILE__, NULL, L"", NULL);
+}
+
+MgFeatureReader* MgLayerBase::InsertFeatures(MgPropertyCollection* properties, MgTransaction* transaction)
+{
+    throw new MgNotImplementedException(L"MgLayerBase.InsertFeatures",
+        __LINE__, __WFILE__, NULL, L"", NULL);
+}
+
+MgFeatureReader* MgLayerBase::InsertFeatures(MgBatchPropertyCollection* properties, MgTransaction* transaction)
+{
+    throw new MgNotImplementedException(L"MgLayerBase.InsertFeatures",
+        __LINE__, __WFILE__, NULL, L"", NULL);
+}
+
+INT32 MgLayerBase::UpdateMatchingFeatures(MgPropertyCollection* properties, CREFSTRING filter, MgTransaction* transaction)
+{
+    throw new MgNotImplementedException(L"MgLayerBase.UpdateMatchingFeatures",
+        __LINE__, __WFILE__, NULL, L"", NULL);
+}
+
+INT32 MgLayerBase::DeleteFeatures(CREFSTRING filter, MgTransaction* transaction)
+{
+    throw new MgNotImplementedException(L"MgLayerBase.DeleteFeatures",
+        __LINE__, __WFILE__, NULL, L"", NULL);
+}
+
+MgSpatialContextReader* MgLayerBase::GetSpatialContexts(bool bActiveOnly)
+{
+    throw new MgNotImplementedException(L"MgLayerBase.GetSpatialContexts",
+        __LINE__, __WFILE__, NULL, L"", NULL);
+}
\ No newline at end of file

Modified: trunk/MgDev/Common/PlatformBase/MapLayer/LayerBase.h
===================================================================
--- trunk/MgDev/Common/PlatformBase/MapLayer/LayerBase.h	2014-10-07 09:31:27 UTC (rev 8393)
+++ trunk/MgDev/Common/PlatformBase/MapLayer/LayerBase.h	2014-10-08 01:36:51 UTC (rev 8394)
@@ -779,6 +779,44 @@
 
     //////////////////////////////////////////////////////////////////
     /// \brief
+    /// Selects features from a feature source according to the
+    /// criteria set in the MgFeatureQueryOptions argument The
+    /// criteria are applied to all of the features in the feature
+    /// source. If you want to apply the criteria to a subset of the
+    /// features, use the \link MgFeatureService::SelectAggregate MgFeatureService::SelectAggregate Method \endlink.
+    /// See \link FiltersAndExpressions Filters and expressions \endlink.
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual MgFeatureReader SelectFeatures(MgFeatureQueryOptions options);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual MgFeatureReader SelectFeatures(MgFeatureQueryOptions options);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual MgFeatureReader SelectFeatures(MgFeatureQueryOptions options);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param options (MgFeatureQueryOptions)
+    /// MgFeatureQueryOptions instance
+    /// containing all required filters for this
+    /// select operation.
+    /// \param coordinateSystem (String/string)
+    /// The WKT string of the coordinate system to transform features to
+    ///
+    /// \return
+    /// Returns an MgFeatureReader containing the set of selected
+    /// features.
+    ///
+    /// \exception MgFeatureServiceException
+    /// \exception MgInvalidArgumentException
+    /// \exception MgFdoException
+    ///
+    /// \since 3.0
+    virtual MgFeatureReader* SelectFeatures(MgFeatureQueryOptions* options, CREFSTRING coordinateSystem);
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
     /// Selects groups of features from a feature source and applies
     /// filters to each of the groups according to the criteria set
     /// in the MgFeatureAggregateOptions argument. If you want to
@@ -870,6 +908,271 @@
     /// \since 1.2
     virtual MgPropertyCollection* UpdateFeatures(MgFeatureCommandCollection* commands);
 
+    ////////////////////////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Starts a transaction on the this layer. The FDO provider indicated by the layer's 
+    /// Feature Source must support transactions.
+    ///
+    /// \remarks
+    /// The XML returned by MgFeatureService::GetCapabilities says
+    /// whether a provider supports transactions. See \link ProviderCapabilities Provider Capabilities \endlink.
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual MgTransaction BeginTransaction();
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual MgTransaction BeginTransaction();
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual MgTransaction BeginTransaction();
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \return
+    /// Returns an MgTransaction instance (or NULL).
+    ///
+    /// \exception MgFeatureServiceException
+    /// \exception MgInvalidArgumentException
+    /// \exception MgInvalidOperationException
+    /// \exception MgFdoException
+    ///
+    /// \since 3.0
+    virtual MgTransaction* BeginTransaction();
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Executes the MgDeleteFeatures, MgInsertFeatures,
+    /// MgUpdateFeatures, MgLockFeatures or MgUnlockFeatures commands
+    /// contained in the given MgFeatureCommandCollection object.
+    ///
+    /// \remarks
+    /// The XML returned by MgFeatureService::GetCapabilities says
+    /// whether a provider supports SQL commands. See \link ProviderCapabilities Provider Capabilities \endlink.
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual MgPropertyCollection UpdateFeatures(MgFeatureCommandCollection commands);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual MgPropertyCollection UpdateFeatures(MgFeatureCommandCollection commands);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual MgPropertyCollection UpdateFeatures(MgFeatureCommandCollection commands);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param commands (MgFeatureCommandCollection)
+    /// A collection of feature commands to be
+    /// executed.
+    /// \param transaction (MgTransaction)
+    /// An optional transaction to execute this operation under
+    ///
+    /// \return
+    /// Returns an MgPropertyCollection object. Each property in the
+    /// collection corresponds to a command in the
+    /// MgFeatureCommandCollection argument. The property name is the
+    /// index of the command in the feature command collection.
+    /// <ul>
+    ///   <li>If the command is of type MgDeleteFeatures, the property
+    ///     type is an MgPropertyType::Int32, and its value is the number
+    ///     of features deleted.</li>
+    ///   <li>If the command is of type MgInsertFeatures, the property
+    ///     type is an MgPropertyType::Feature, and its value is a
+    ///     MgFeatureReader object. The feature reader object contains
+    ///     the set of properties inserted into the datastore by the
+    ///     insert command.</li>
+    ///   <li>If the command is of type MgUpdateFeatures, the property
+    ///     type is MgPropertyType::Int32, and its value is the number of
+    ///     features updated.</li>
+    ///   <li>If the command is of type MgLockFeatures, the property
+    ///     type is MgPropertyType::Feature, and its value is the number
+    ///     of features locked.</li>
+    ///   <li>If the command is of type MgUnLockFeatures, the property
+    ///     type is MgPropertyType::Int32, and its value is the number of
+    ///     features unlocked.</li>
+    /// </ul>
+    ///
+    /// \exception MgFeatureServiceException
+    /// \exception MgInvalidArgumentException
+    /// \exception MgInvalidOperationException
+    /// \exception MgFdoException
+    ///
+    /// \since 3.0
+    virtual MgPropertyCollection* UpdateFeatures(MgFeatureCommandCollection* commands, MgTransaction* transaction);
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Inserts a new feature into the specified feature class of the specified Feature Source
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual MgFeatureReader InsertFeatures(MgPropertyCollection properties);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual MgFeatureReader InsertFeatures(MgPropertyCollection properties);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual MgFeatureReader InsertFeatures(MgPropertyCollection properties);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param properties (MgPropertyCollection)
+    /// The collection of property values to insert
+    /// \param transaction (MgTransaction)
+    /// An optional transaction to execute this operation under
+    ///
+    /// \return
+    /// Returns a feature reader object that contains the set of properties 
+    /// inserted into the datastore by the insert command.
+    ///
+    /// \remarks
+    /// Remember to close any feature readers returned by this method, even if you don't intend
+    /// to do anything with them
+    ///
+    /// \exception MgFeatureServiceException
+    /// \exception MgInvalidArgumentException
+    /// \exception MgInvalidOperationException
+    /// \exception MgFdoException
+    ///
+    /// \since 3.0
+    virtual MgFeatureReader* InsertFeatures(MgPropertyCollection* properties, MgTransaction* transaction);
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Inserts a set of new features into the specified feature class of the specified Feature Source
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual MgFeatureReader InsertFeatures(MgBatchPropertyCollection properties);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual MgFeatureReader InsertFeatures(MgBatchPropertyCollection properties);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual MgFeatureReader InsertFeatures(MgBatchPropertyCollection properties);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param properties (MgBatchPropertyCollection)
+    /// The collection of property values to insert. Each MgPropertyCollection within 
+    /// this collection represents property values for a single feature to insert
+    /// \param transaction (MgTransaction)
+    /// An optional transaction to execute this operation under
+    ///
+    /// \return
+    /// Returns a feature reader object that contains the set of properties 
+    /// inserted into the datastore by the insert command.
+    ///
+    /// \remarks
+    /// Remember to close any feature readers returned by this method, even if you don't intend
+    /// to do anything with them
+    ///
+    /// \exception MgFeatureServiceException
+    /// \exception MgInvalidArgumentException
+    /// \exception MgInvalidOperationException
+    /// \exception MgFdoException
+    ///
+    /// \since 3.0
+    virtual MgFeatureReader* InsertFeatures(MgBatchPropertyCollection* properties, MgTransaction* transaction);
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Updates all features that match the given filter with the specified property values
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual int UpdateMatchingFeatures(MgPropertyCollection properties, string filter);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual int UpdateMatchingFeatures(MgPropertyCollection properties, String filter);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual int UpdateMatchingFeatures(MgPropertyCollection properties, String filter);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param properties (MgBatchPropertyCollection)
+    /// The property values to update matching features with
+    /// \param filter (String/string)
+    /// The FDO filter string that detemines what features will be updated
+    /// \param transaction (MgTransaction)
+    /// An optional transaction to execute this operation under
+    ///
+    /// \return
+    /// Returns the number of features updated by this operation
+    ///
+    /// \exception MgFeatureServiceException
+    /// \exception MgInvalidArgumentException
+    /// \exception MgInvalidOperationException
+    /// \exception MgFdoException
+    ///
+    /// \since 3.0
+    virtual INT32 UpdateMatchingFeatures(MgPropertyCollection* properties, CREFSTRING filter, MgTransaction* transaction);
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Deletes all features that match the given filter
+    ///
+    /// \remarks
+    /// Transactions will be used internally if the provider supports them
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual int DeleteFeatures(string filter);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual int DeleteFeatures(String filter);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual int DeleteFeatures(String filter);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param filter (String/string)
+    /// The FDO filter string that detemines what features will be deleted
+    /// \param transaction (MgTransaction)
+    /// An optional transaction to execute this operation under
+    ///
+    /// \return
+    /// Returns the number of features deleted by this operation
+    ///
+    /// \exception MgFeatureServiceException
+    /// \exception MgInvalidArgumentException
+    /// \exception MgInvalidOperationException
+    /// \exception MgFdoException
+    ///
+    /// \since 3.0
+    virtual INT32 DeleteFeatures(CREFSTRING filter, MgTransaction* transaction);
+
+    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Gets all of the spatial contexts available in the layer or just the active one
+    ///
+    /// \remarks
+    /// The \link FdoSpatialContextList_schema FdoSpatialContextList \endlink XML schema contains
+    /// a specification of the content of the spatial context
+    /// information returned in the MgSpatialContextReader object.
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual MgSpatialContextReader GetSpatialContexts(bool bActiveOnly);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual MgSpatialContextReader GetSpatialContexts(boolean bActiveOnly);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual MgSpatialContextReader GetSpatialContexts(bool bActiveOnly);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param bActiveOnly (boolean/bool)
+    /// This flag is obsolete and no longer used.
+    ///
+    /// \return
+    /// Returns an MgSpatialContextReader object.
+    ///
+    /// \exception MgFeatureServiceException
+    /// \exception MgInvalidArgumentException
+    /// \exception MgInvalidOperationException
+    /// \exception MgFdoException
+    ///
+    /// \since 3.0
+    virtual MgSpatialContextReader* GetSpatialContexts(bool bActiveOnly);
+
 INTERNAL_API:
 
     static MdfModel::LayerDefinition* GetLayerDefinition(MgResourceService* svcResource, MgResourceIdentifier* resId);

Modified: trunk/MgDev/Common/PlatformBase/Services/FeatureDefs.h
===================================================================
--- trunk/MgDev/Common/PlatformBase/Services/FeatureDefs.h	2014-10-07 09:31:27 UTC (rev 8393)
+++ trunk/MgDev/Common/PlatformBase/Services/FeatureDefs.h	2014-10-08 01:36:51 UTC (rev 8394)
@@ -77,6 +77,12 @@
     static const int AddSavePoint_Id                      = 0x1111ED2E;
     static const int RollbackSavePoint_Id                 = 0x1111ED2F;
     static const int ReleaseSavePoint_Id                  = 0x1111ED30;
+
+    static const int InsertFeatures         = 0x1111ED31;
+    static const int InsertFeatures2        = 0x1111ED32;
+    static const int UpdateMatchingFeatures = 0x1111ED33;
+    static const int DeleteFeatures         = 0x1111ED34;
+    static const int SelectFeaturesWithTransform = 0x1111ED35;
 };
 /// \endcond
 

Modified: trunk/MgDev/Common/PlatformBase/Services/FeatureService.h
===================================================================
--- trunk/MgDev/Common/PlatformBase/Services/FeatureService.h	2014-10-07 09:31:27 UTC (rev 8393)
+++ trunk/MgDev/Common/PlatformBase/Services/FeatureService.h	2014-10-08 01:36:51 UTC (rev 8394)
@@ -981,6 +981,342 @@
                                                  MgFeatureCommandCollection* commands,
                                                  MgTransaction* transaction) = 0;
 
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Inserts a new feature into the specified feature class of the specified Feature Source
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual MgFeatureReader InsertFeatures(MgResourceIdentifier resource, string className, MgPropertyCollection propertyValues);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual MgFeatureReader InsertFeatures(MgResourceIdentifier resource, String className, MgPropertyCollection propertyValues);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual MgFeatureReader InsertFeatures(MgResourceIdentifier resource, String className, MgPropertyCollection propertyValues);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param resource (MgResourceIdentifier)
+    /// A resource identifier for the feature
+    /// source.
+    /// \param className (String/string)
+    /// The name of the feature class on which
+    /// the insert operation is performed.
+    /// \param propertyValues (MgPropertyCollection)
+    /// The collection of property values to insert
+    ///
+    /// \return
+    /// Returns a feature reader object that contains the set of properties 
+    /// inserted into the datastore by the insert command.
+    ///
+    /// \remarks
+    /// Remember to close any feature readers returned by this method, even if you don't intend
+    /// to do anything with them
+    ///
+    /// \exception MgFeatureServiceException
+    /// \exception MgInvalidArgumentException
+    /// \exception MgInvalidOperationException
+    /// \exception MgFdoException
+    ///
+    /// \since 3.0
+    virtual MgFeatureReader* InsertFeatures(MgResourceIdentifier* resource,
+                                            CREFSTRING className,
+                                            MgPropertyCollection* propertyValues) = 0;
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Inserts a new feature into the specified feature class of the specified Feature Source
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual MgFeatureReader InsertFeatures(MgResourceIdentifier resource, string className, MgPropertyCollection propertyValues, MgTransaction trans);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual MgFeatureReader InsertFeatures(MgResourceIdentifier resource, String className, MgPropertyCollection propertyValues, MgTransaction trans);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual MgFeatureReader InsertFeatures(MgResourceIdentifier resource, String className, MgPropertyCollection propertyValues, MgTransaction trans);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param resource (MgResourceIdentifier)
+    /// A resource identifier for the feature
+    /// source.
+    /// \param className (String/string)
+    /// The name of the feature class on which
+    /// the insert operation is performed.
+    /// \param propertyValues (MgPropertyCollection)
+    /// The collection of property values to insert
+    /// \param trans (MgTransaction)
+    /// The transaction to execute this operation under
+    ///
+    /// \return
+    /// Returns a feature reader object that contains the set of properties 
+    /// inserted into the datastore by the insert command.
+    ///
+    /// \remarks
+    /// Remember to close any feature readers returned by this method, even if you don't intend
+    /// to do anything with them
+    ///
+    /// \exception MgFeatureServiceException
+    /// \exception MgInvalidArgumentException
+    /// \exception MgInvalidOperationException
+    /// \exception MgFdoException
+    ///
+    /// \since 3.0
+    virtual MgFeatureReader* InsertFeatures(MgResourceIdentifier* resource,
+                                            CREFSTRING className,
+                                            MgPropertyCollection* propertyValues,
+                                            MgTransaction* trans) = 0;
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Inserts a set of new features into the specified feature class of the specified Feature Source
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual MgFeatureReader InsertFeatures(MgResourceIdentifier resource, string className, MgBatchPropertyCollection batchPropertyValues);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual MgFeatureReader InsertFeatures(MgResourceIdentifier resource, String className, MgBatchPropertyCollection batchPropertyValues);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual MgFeatureReader InsertFeatures(MgResourceIdentifier resource, String className, MgBatchPropertyCollection batchPropertyValues);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param resource (MgResourceIdentifier)
+    /// A resource identifier for the feature
+    /// source.
+    /// \param className (String/string)
+    /// The name of the feature class on which
+    /// the insert operation is performed.
+    /// \param batchPropertyValues (MgBatchPropertyCollection)
+    /// The collection of property values to insert. Each MgPropertyCollection within 
+    /// this collection represents property values for a single feature to insert
+    ///
+    /// \return
+    /// Returns a feature reader object that contains the set of properties 
+    /// inserted into the datastore by the insert command.
+    ///
+    /// \remarks
+    /// Remember to close any feature readers returned by this method, even if you don't intend
+    /// to do anything with them
+    ///
+    /// \exception MgFeatureServiceException
+    /// \exception MgInvalidArgumentException
+    /// \exception MgInvalidOperationException
+    /// \exception MgFdoException
+    ///
+    /// \since 3.0
+    virtual MgFeatureReader* InsertFeatures(MgResourceIdentifier* resource,
+                                            CREFSTRING className,
+                                            MgBatchPropertyCollection* batchPropertyValues) = 0;
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Inserts a set of new features into the specified feature class of the specified Feature Source
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual MgFeatureReader InsertFeatures(MgResourceIdentifier resource, string className, MgBatchPropertyCollection batchPropertyValues, MgTransaction trans);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual MgFeatureReader InsertFeatures(MgResourceIdentifier resource, String className, MgBatchPropertyCollection batchPropertyValues, MgTransaction trans);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual MgFeatureReader InsertFeatures(MgResourceIdentifier resource, String className, MgBatchPropertyCollection batchPropertyValues, MgTransaction trans);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param resource (MgResourceIdentifier)
+    /// A resource identifier for the feature
+    /// source.
+    /// \param className (String/string)
+    /// The name of the feature class on which
+    /// the insert operation is performed.
+    /// \param batchPropertyValues (MgBatchPropertyCollection)
+    /// The collection of property values to insert. Each MgPropertyCollection within 
+    /// this collection represents property values for a single feature to insert
+    /// \param trans (MgTransaction)
+    /// The transaction to execute this operation under
+    ///
+    /// \return
+    /// Returns a feature reader object that contains the set of properties 
+    /// inserted into the datastore by the insert command.
+    ///
+    /// \remarks
+    /// Remember to close any feature readers returned by this method, even if you don't intend
+    /// to do anything with them
+    ///
+    /// \exception MgFeatureServiceException
+    /// \exception MgInvalidArgumentException
+    /// \exception MgInvalidOperationException
+    /// \exception MgFdoException
+    ///
+    /// \since 3.0
+    virtual MgFeatureReader* InsertFeatures(MgResourceIdentifier* resource,
+                                            CREFSTRING className,
+                                            MgBatchPropertyCollection* batchPropertyValues,
+                                            MgTransaction* trans) = 0;
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Updates all features that match the given filter with the specified property values
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual int UpdateMatchingFeatures(MgResourceIdentifier resource, string className, MgPropertyCollection properties, string filter);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual int UpdateMatchingFeatures(MgResourceIdentifier resource, String className, MgPropertyCollection properties, String filter);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual int UpdateMatchingFeatures(MgResourceIdentifier resource, String className, MgPropertyCollection properties, String filter);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param resource (MgResourceIdentifier)
+    /// A resource identifier for the feature
+    /// source.
+    /// \param className (String/string)
+    /// The name of the feature class on which
+    /// the update operation is performed.
+    /// \param properties (MgBatchPropertyCollection)
+    /// The property values to update matching features with
+    /// \param filter (String/string)
+    /// The FDO filter string that detemines what features will be updated
+    ///
+    /// \return
+    /// Returns the number of features updated by this operation
+    ///
+    /// \exception MgFeatureServiceException
+    /// \exception MgInvalidArgumentException
+    /// \exception MgInvalidOperationException
+    /// \exception MgFdoException
+    ///
+    /// \since 3.0
+    virtual INT32 UpdateMatchingFeatures(MgResourceIdentifier* resource,
+                                         CREFSTRING className,
+                                         MgPropertyCollection* properties,
+                                         CREFSTRING filter) = 0;
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Updates all features that match the given filter with the specified property values
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual int UpdateMatchingFeatures(MgResourceIdentifier resource, string className, MgPropertyCollection properties, string filter, MgTransaction trans);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual int UpdateMatchingFeatures(MgResourceIdentifier resource, String className, MgPropertyCollection properties, String filter, MgTransaction trans);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual int UpdateMatchingFeatures(MgResourceIdentifier resource, String className, MgPropertyCollection properties, String filter, MgTransaction trans);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param resource (MgResourceIdentifier)
+    /// A resource identifier for the feature
+    /// source.
+    /// \param className (String/string)
+    /// The name of the feature class on which
+    /// the update operation is performed.
+    /// \param properties (MgBatchPropertyCollection)
+    /// The property values to update matching features with
+    /// \param filter (String/string)
+    /// The FDO filter string that detemines what features will be updated
+    /// \param trans (MgTransaction)
+    /// The transaction to execute this operation under
+    ///
+    /// \return
+    /// Returns the number of features updated by this operation
+    ///
+    /// \exception MgFeatureServiceException
+    /// \exception MgInvalidArgumentException
+    /// \exception MgInvalidOperationException
+    /// \exception MgFdoException
+    ///
+    /// \since 3.0
+    virtual INT32 UpdateMatchingFeatures(MgResourceIdentifier* resource,
+                                         CREFSTRING className,
+                                         MgPropertyCollection* properties,
+                                         CREFSTRING filter,
+                                         MgTransaction* trans) = 0;
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Deletes all features that match the given filter
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual int DeleteFeatures(MgResourceIdentifier resource, string className, string filter);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual int DeleteFeatures(MgResourceIdentifier resource, String className, String filter);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual int DeleteFeatures(MgResourceIdentifier resource, String className, String filter);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param resource (MgResourceIdentifier)
+    /// A resource identifier for the feature
+    /// source.
+    /// \param className (String/string)
+    /// The name of the feature class on which
+    /// the delete operation is performed.
+    /// \param filter (String/string)
+    /// The FDO filter string that detemines what features will be deleted
+    ///
+    /// \return
+    /// Returns the number of features deleted by this operation
+    ///
+    /// \exception MgFeatureServiceException
+    /// \exception MgInvalidArgumentException
+    /// \exception MgInvalidOperationException
+    /// \exception MgFdoException
+    ///
+    /// \since 3.0
+    virtual INT32 DeleteFeatures(MgResourceIdentifier* resource,
+                                 CREFSTRING className,
+                                 CREFSTRING filter) = 0;
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Deletes all features that match the given filter
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual int DeleteFeatures(MgResourceIdentifier resource, string className, string filter, MgTransaction trans);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual int DeleteFeatures(MgResourceIdentifier resource, String className, String filter, MgTransaction trans);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual int DeleteFeatures(MgResourceIdentifier resource, String className, String filter, MgTransaction trans);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param resource (MgResourceIdentifier)
+    /// A resource identifier for the feature
+    /// source.
+    /// \param className (String/string)
+    /// The name of the feature class on which
+    /// the delete operation is performed.
+    /// \param filter (String/string)
+    /// The FDO filter string that detemines what features will be deleted
+    /// \param trans (MgTransaction)
+    /// The transaction to execute this operation under
+    ///
+    /// \return
+    /// Returns the number of features deleted by this operation
+    ///
+    /// \exception MgFeatureServiceException
+    /// \exception MgInvalidArgumentException
+    /// \exception MgInvalidOperationException
+    /// \exception MgFdoException
+    ///
+    /// \since 3.0
+    virtual INT32 DeleteFeatures(MgResourceIdentifier* resource,
+                                 CREFSTRING className,
+                                 CREFSTRING filter,
+                                 MgTransaction* trans) = 0;
+
     ////////////////////////////////////////////////////////////////////////////////////////////////
     /// \brief
     /// Gets the locked features

Modified: trunk/MgDev/Common/PlatformBase/Services/ResourceDefs.h
===================================================================
--- trunk/MgDev/Common/PlatformBase/Services/ResourceDefs.h	2014-10-07 09:31:27 UTC (rev 8393)
+++ trunk/MgDev/Common/PlatformBase/Services/ResourceDefs.h	2014-10-08 01:36:51 UTC (rev 8394)
@@ -550,10 +550,10 @@
 ///
 class MG_PLATFORMBASE_API MgResourceHeaderProperties
 {
-INTERNAL_API:
-    static const INT32 General  = 0x00000001;
-    static const INT32 Security = 0x00000002;
-    static const INT32 Metadata = 0x00000004;
+EXTERNAL_API:
+    static const INT32 General  = 1;
+    static const INT32 Security = 2;
+    static const INT32 Metadata = 4;
 };
 /// \endcond
 

Modified: trunk/MgDev/Common/PlatformBase/Services/ResourceService.h
===================================================================
--- trunk/MgDev/Common/PlatformBase/Services/ResourceService.h	2014-10-07 09:31:27 UTC (rev 8393)
+++ trunk/MgDev/Common/PlatformBase/Services/ResourceService.h	2014-10-08 01:36:51 UTC (rev 8394)
@@ -1773,35 +1773,6 @@
 
     ///////////////////////////////////////////////////////////////////////////
     /// \brief
-    /// Enumerate the resource documents in the specified repository.
-    ///
-    /// \remarks
-    /// This method only works on "Library".
-    ///
-    /// \param resources
-    /// Resource identifiers specifying the resources to enumerate.
-    /// \n If it is null or contains no resource, then the type must be specified.
-    /// \n If it is not null and contains some resource, then the type will be ignored.
-    /// \param type
-    /// Type of the resource to be enumerated. See MgResourceType for valid types.
-    /// No folder type is allowed.
-    /// \param properties
-    /// Flag to specify which properties of the resource header should be filtered.
-    /// It may be set to 0 or by bitwise inclusively OR'ing together one or
-    /// more of the MgResourceHeaderProperties values.
-    ///
-    /// \return
-    /// Returns a string containing a description of the WMS layer definitions
-    /// in XML format using the \link ResourceList_schema ResourceList \endlink
-    /// schema.
-    ///
-    /// \exception MgInvalidResourceTypeException
-    ///
-    virtual STRING EnumerateResourceDocuments(MgStringCollection* resources,
-        CREFSTRING type, INT32 properties);
-
-    ///////////////////////////////////////////////////////////////////////////
-    /// \brief
     /// Gets the content of the specified resource.
     ///
     /// \param resource
@@ -1848,34 +1819,6 @@
 
     ///////////////////////////////////////////////////////////////////////////
     /// \brief
-    /// Returns the modified date of the specified resource.
-    ///
-    /// This method only works on "Library" repository.
-    ///
-    /// <!-- Syntax in .Net, Java, and PHP -->
-    /// \htmlinclude DotNetSyntaxTop.html
-    /// virtual MgDateTime GetResourceModifiedDate(MgResourceIdentifier resource);
-    /// \htmlinclude SyntaxBottom.html
-    /// \htmlinclude JavaSyntaxTop.html
-    /// virtual MgDateTime GetResourceModifiedDate(MgResourceIdentifier resource);
-    /// \htmlinclude SyntaxBottom.html
-    /// \htmlinclude PHPSyntaxTop.html
-    /// virtual MgDateTime GetResourceModifiedDate(MgResourceIdentifier resource);
-    /// \htmlinclude SyntaxBottom.html
-    ///
-    /// \param resource (MgResourceIdentifier)
-    /// Resource to get the modified date for.
-    ///
-    /// \return
-    /// An MgDateTime object containing the modified date of the resource.
-    ///
-    /// \exception MgInvalidRepositoryTypeException
-    /// \exception MgInvalidResourceTypeException
-    ///
-    virtual MgDateTime* GetResourceModifiedDate(MgResourceIdentifier* resource) = 0;
-
-    ///////////////////////////////////////////////////////////////////////////
-    /// \brief
     /// Enumerate all the parent Map Definition resources of the specified
     /// resources.
     ///
@@ -1927,6 +1870,65 @@
     virtual bool HasPermission(MgResourceIdentifier* resource, CREFSTRING permission);
 
 EXTERNAL_API:
+    ///////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Enumerate the resource documents in the specified repository.
+    ///
+    /// \remarks
+    /// This method only works on "Library".
+    /// This API has been promoted from internal to un-published status for MapGuide Open Source 3.0
+    ///
+    /// \param resources
+    /// Resource identifiers specifying the resources to enumerate.
+    /// \n If it is null or contains no resource, then the type must be specified.
+    /// \n If it is not null and contains some resource, then the type will be ignored.
+    /// \param type
+    /// Type of the resource to be enumerated. See MgResourceType for valid types.
+    /// No folder type is allowed.
+    /// \param properties
+    /// Flag to specify which properties of the resource header should be filtered.
+    /// It may be set to 0 or by bitwise inclusively OR'ing together one or
+    /// more of the MgResourceHeaderProperties values.
+    ///
+    /// \return
+    /// Returns a string containing a description of the WMS layer definitions
+    /// in XML format using the \link ResourceList_schema ResourceList \endlink
+    /// schema.
+    ///
+    /// \exception MgInvalidResourceTypeException
+    ///
+    virtual STRING EnumerateResourceDocuments(MgStringCollection* resources,
+        CREFSTRING type, INT32 properties);
+        
+    ///////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Returns the modified date of the specified resource.
+    ///
+    /// \remarks
+    /// This method only works on "Library" repository.
+    /// This API has been promoted from internal to un-published status for MapGuide Open Source 3.0
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual MgDateTime GetResourceModifiedDate(MgResourceIdentifier resource);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual MgDateTime GetResourceModifiedDate(MgResourceIdentifier resource);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual MgDateTime GetResourceModifiedDate(MgResourceIdentifier resource);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param resource (MgResourceIdentifier)
+    /// Resource to get the modified date for.
+    ///
+    /// \return
+    /// An MgDateTime object containing the modified date of the resource.
+    ///
+    /// \exception MgInvalidRepositoryTypeException
+    /// \exception MgInvalidResourceTypeException
+    ///
+    virtual MgDateTime* GetResourceModifiedDate(MgResourceIdentifier* resource) = 0;
 
     /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
     /// \brief


Property changes on: trunk/MgDev/Desktop
___________________________________________________________________
Modified: svn:mergeinfo
   - /branches/2.4/MgDev/Desktop:6749-6756,6777-6783,6785-6787,6789,6791-6794,6796-6801,6954-6962,6986-7006,7152
/branches/2.5/MgDev/Desktop:7511
/branches/2.6/MgDev/Desktop:8276-8286,8314-8315
/sandbox/jng/createruntimemap/Desktop:7486-7555
/sandbox/jng/dwftk/Desktop:8321-8324,8328-8329,8331,8352
/sandbox/jng/geos34x/Desktop:8256-8259
/sandbox/jng/v30/Desktop:8215-8216,8218-8219
/sandbox/rfc94/Desktop:5099-5163
   + /branches/2.4/MgDev/Desktop:7152
/branches/2.5/MgDev/Desktop:7511
/branches/2.6/MgDev/Desktop:8276-8286,8314-8315
/sandbox/jng/convenience_apis/Desktop:8271-8363
/sandbox/jng/createruntimemap/Desktop:7486-7555
/sandbox/jng/dwftk/Desktop:8321-8324,8328-8329,8331,8352
/sandbox/jng/geos34x/Desktop:8256-8259
/sandbox/jng/v30/Desktop:8215-8216,8218-8219
/sandbox/rfc94/Desktop:5099-5163

Modified: trunk/MgDev/Desktop/MgDesktop/MapLayer/Layer.cpp
===================================================================
--- trunk/MgDev/Desktop/MgDesktop/MapLayer/Layer.cpp	2014-10-07 09:31:27 UTC (rev 8393)
+++ trunk/MgDev/Desktop/MgDesktop/MapLayer/Layer.cpp	2014-10-08 01:36:51 UTC (rev 8394)
@@ -378,6 +378,24 @@
     return propCol.Detach();
 }
 
+MgPropertyCollection* MgdLayer::UpdateFeatures(MgFeatureCommandCollection* commands, MgTransaction* trans)
+{
+    Ptr<MgPropertyCollection> propCol;
+
+    MG_TRY()
+
+    Ptr<MgResourceIdentifier> resourceId = new MgResourceIdentifier(m_featureSourceId);
+
+    Ptr<MgFeatureService> featureService = dynamic_cast<MgFeatureService*>(
+        GetMap()->GetService(MgServiceType::FeatureService));
+
+    propCol = featureService->UpdateFeatures(resourceId, commands, trans);
+
+    MG_CATCH_AND_THROW(L"MgdLayer.UpdateFeatures")
+
+    return propCol.Detach();
+}
+
 MgTransaction* MgdLayer::BeginTransaction()
 {
     Ptr<MgTransaction> trans;
@@ -442,7 +460,7 @@
     return reader.Detach();
 }
 
-int MgdLayer::UpdateFeatures(MgPropertyCollection* propertyValues, CREFSTRING filter)
+INT32 MgdLayer::UpdateMatchingFeatures(MgPropertyCollection* propertyValues, CREFSTRING filter)
 {
     int updated = 0;
 
@@ -451,14 +469,14 @@
     Ptr<MgdFeatureService> featSvc = static_cast<MgdFeatureService*>(GetMap()->GetService(MgServiceType::FeatureService));
     Ptr<MgResourceIdentifier> fsId = new MgResourceIdentifier(GetFeatureSourceId());
 
-    updated = featSvc->UpdateFeatures(fsId, GetFeatureClassName(), propertyValues, filter);
+    updated = featSvc->UpdateMatchingFeatures(fsId, GetFeatureClassName(), propertyValues, filter);
 
-    MG_CATCH_AND_THROW(L"MgdLayer.UpdateFeatures")
+    MG_CATCH_AND_THROW(L"MgdLayer.UpdateMatchingFeatures")
 
     return updated;
 }
 
-int MgdLayer::DeleteFeatures(CREFSTRING filter)
+INT32 MgdLayer::DeleteFeatures(CREFSTRING filter)
 {
     int deleted = 0;
 
@@ -490,7 +508,7 @@
     return reader.Detach();
 }
 
-int MgdLayer::UpdateFeatures(MgPropertyCollection* propertyValues, CREFSTRING filter, MgTransaction* trans)
+INT32 MgdLayer::UpdateMatchingFeatures(MgPropertyCollection* propertyValues, CREFSTRING filter, MgTransaction* trans)
 {
     int updated = 0;
 
@@ -499,14 +517,14 @@
     Ptr<MgdFeatureService> featSvc = static_cast<MgdFeatureService*>(GetMap()->GetService(MgServiceType::FeatureService));
     Ptr<MgResourceIdentifier> fsId = new MgResourceIdentifier(GetFeatureSourceId());
 
-    updated = featSvc->UpdateFeatures(fsId, GetFeatureClassName(), propertyValues, filter, trans);
+    updated = featSvc->UpdateMatchingFeatures(fsId, GetFeatureClassName(), propertyValues, filter, trans);
 
-    MG_CATCH_AND_THROW(L"MgdLayer.UpdateFeatures")
+    MG_CATCH_AND_THROW(L"MgdLayer.UpdateMatchingFeatures")
 
     return updated;
 }
 
-int MgdLayer::DeleteFeatures(CREFSTRING filter, MgTransaction* trans)
+INT32 MgdLayer::DeleteFeatures(CREFSTRING filter, MgTransaction* trans)
 {
     int deleted = 0;
 

Modified: trunk/MgDev/Desktop/MgDesktop/MapLayer/Layer.h
===================================================================
--- trunk/MgDev/Desktop/MgDesktop/MapLayer/Layer.h	2014-10-07 09:31:27 UTC (rev 8393)
+++ trunk/MgDev/Desktop/MgDesktop/MapLayer/Layer.h	2014-10-08 01:36:51 UTC (rev 8394)
@@ -23,19 +23,21 @@
 
     virtual MgPropertyCollection* UpdateFeatures(MgFeatureCommandCollection* commands);
 
+    virtual MgPropertyCollection* UpdateFeatures(MgFeatureCommandCollection* commands, MgTransaction* trans);
+
     virtual MgTransaction* BeginTransaction();
 
     virtual MgdScrollableFeatureReader* SelectFeaturesExtended(MgFeatureQueryOptions* options);
 
     virtual MgFeatureReader* InsertFeatures(MgPropertyCollection* propertyValues);
 
-	virtual INT32 UpdateFeatures(MgPropertyCollection* propertyValues, CREFSTRING filter);
+    virtual INT32 UpdateMatchingFeatures(MgPropertyCollection* propertyValues, CREFSTRING filter);
 
 	virtual INT32 DeleteFeatures(CREFSTRING filter);
 
     virtual MgFeatureReader* InsertFeatures(MgPropertyCollection* propertyValues, MgTransaction* trans);
 
-	virtual INT32 UpdateFeatures(MgPropertyCollection* propertyValues, CREFSTRING filter, MgTransaction* trans);
+	virtual INT32 UpdateMatchingFeatures(MgPropertyCollection* propertyValues, CREFSTRING filter, MgTransaction* trans);
 
 	virtual INT32 DeleteFeatures(CREFSTRING filter, MgTransaction* trans);
 

Modified: trunk/MgDev/Desktop/MgDesktop/MgDesktop.vcxproj
===================================================================
--- trunk/MgDev/Desktop/MgDesktop/MgDesktop.vcxproj	2014-10-07 09:31:27 UTC (rev 8393)
+++ trunk/MgDev/Desktop/MgDesktop/MgDesktop.vcxproj	2014-10-08 01:36:51 UTC (rev 8394)
@@ -208,7 +208,7 @@
     <Link>
       <AdditionalDependencies>FDO.lib;FDOCommon.lib;FDOGeometry.lib;ExpressionEngine.lib;ACE.lib;MgFoundation.lib;MgGeometry.lib;MgMdfModel.lib;MgMdfParser.lib;MgPlatformBase.lib;MgRenderers.lib;MgStylization.lib;MgGwsCommon.lib;MgGwsQueryEngine.lib;xerces-c_3mg.lib;dwfcore_wt.1.7.0.lib;dwftk_wt.7.7.0.lib;w3dtk_wt.1.7.1555.lib;whiptk_wt.7.13.601.lib;MgSecurity.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <OutputFile>$(OutDir)$(ProjectName).dll</OutputFile>
-      <AdditionalLibraryDirectories>..\..\Oem\ACE\ACE_wrappers\lib64\$(Configuration);..\..\Oem\FDO\Lib64;..\..\Oem\DWFTK\develop\global\lib\static\$(Configuration)64\vc10.0;..\..\Oem\dbxml\xerces-c-src\Build\$(Configuration)64;..\..\Common\lib\$(Configuration)64;..\..\Server\lib\$(Configuration)64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <AdditionalLibraryDirectories>..\..\Oem\ACE\ACE_wrappers\lib64\$(Configuration);..\..\Oem\FDO\Lib64;..\..\Oem\DWFTK\develop\global\lib\x64\static\$(Configuration)\vc10.0;..\..\Oem\dbxml\xerces-c-src\Build\$(Configuration)64;..\..\Common\lib\$(Configuration)64;..\..\Server\lib\$(Configuration)64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
       <DelayLoadDLLs>MgMdfParser.dll;MgGeometry.dll;MgGwsCommon.dll;MgGwsResource.dll;FDO.dll;FDOCommon.dll;MgStylization.dll;FDOGeometry.dll;ExpressionEngine.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <SubSystem>Windows</SubSystem>

Modified: trunk/MgDev/Desktop/MgDesktop/Services/Feature/Commands/UpdateFeatures.cpp
===================================================================
--- trunk/MgDev/Desktop/MgDesktop/Services/Feature/Commands/UpdateFeatures.cpp	2014-10-07 09:31:27 UTC (rev 8393)
+++ trunk/MgDev/Desktop/MgDesktop/Services/Feature/Commands/UpdateFeatures.cpp	2014-10-08 01:36:51 UTC (rev 8394)
@@ -277,116 +277,6 @@
     return reader.Detach();
 }
 
-
-MgPropertyCollection* MgdUpdateFeaturesCommand::ExecuteInsert(MgResourceIdentifier* resource, CREFSTRING className, MgBatchPropertyCollection* batchPropertyValues, MgTransaction* trans)
-{
-    Ptr<MgPropertyCollection> ret;
-
-    MG_FEATURE_SERVICE_TRY()
-
-    CHECK_FEATURE_SOURCE_ARGUMENT(resource, L"MgdUpdateFeaturesCommand::ExecuteInsert");
-	CHECKARGUMENTNULL(batchPropertyValues, L"MgdUpdateFeaturesCommand::ExecuteInsert");
-	if (className.empty())
-		throw new MgNullArgumentException(L"MgdUpdateFeaturesCommand::ExecuteInsert", __LINE__, __WFILE__, NULL, L"", NULL);
-	
-    ret = new MgPropertyCollection();
-
-    Ptr<MgdFeatureConnection> connWrap;
-	FdoPtr<FdoIConnection> conn;
-    FdoPtr<FdoITransaction> fdoTrans;
-    Ptr<MgdTransaction> mgTrans = dynamic_cast<MgdTransaction*>(trans);
-    if (NULL != mgTrans)
-    {
-        SAFE_ADDREF(mgTrans.p);
-        Ptr<MgResourceIdentifier> origFeatureSource = mgTrans->GetFeatureSource();
-        //Check that the transaction originates from the same feature source
-        if (origFeatureSource->ToString() != resource->ToString())
-            throw new MgInvalidArgumentException(L"MgdUpdateFeaturesCommand::ExecuteInsert", __LINE__, __WFILE__, NULL, L"", NULL);
-
-        connWrap = mgTrans->GetConnection(); //Connection is already open
-        fdoTrans = mgTrans->GetFdoTransaction();
-    }
-    else
-    {    
-        connWrap = new MgdFeatureConnection(resource);
-    }
-
-    conn = connWrap->GetConnection();
-	FdoPtr<FdoIInsert> insert = (FdoIInsert*)conn->CreateCommand(FdoCommandType_Insert);
-	
-	insert->SetFeatureClassName(className.c_str());
-
-	FdoPtr<FdoPropertyValueCollection> propVals = insert->GetPropertyValues();
-	
-    if (NULL != fdoTrans.p)
-        insert->SetTransaction(fdoTrans);
-
-    //TODO: Support batch parameters, the main beneficiary of this API. Even then,
-    //the value flipping approach employed here has performance benefits for certain
-    //providers, like SQLite
-
-    for (INT32 i = 0; i < batchPropertyValues->GetCount(); i++)
-    {
-        Ptr<MgPropertyCollection> propertyValues = batchPropertyValues->GetItem(i);
-
-        //First feature, set up the FDO property value collection
-        if (i == 0)
-        {
-            for (INT32 i = 0; i < propertyValues->GetCount(); i++)
-	        {
-		        Ptr<MgProperty> mgp = propertyValues->GetItem(i);
-		        FdoPtr<FdoPropertyValue> pv = MgdFeatureUtil::MgPropertyToFdoProperty(mgp);
-
-		        propVals->Add(pv);
-	        }
-        }
-        else //Feature after the first
-        {
-            //Set all to null
-            for (INT32 i = 0; i < propVals->GetCount(); i++)
-            {
-                FdoPtr<FdoPropertyValue> fp = propVals->GetItem(i);
-                FdoPtr<FdoValueExpression> expr = fp->GetValue();
-                FdoDataValue* fdv = dynamic_cast<FdoDataValue*>(expr.p);
-                FdoGeometryValue* fgv = dynamic_cast<FdoGeometryValue*>(expr.p);
-                if (fdv)
-                {
-                    fdv->SetNull();
-                }
-                else if (fgv)
-                {
-                    fgv->SetNullValue();
-                }
-            }
-
-            //Now set the appropriate values. MgdFeatureUtil does the work
-            for (INT32 i = 0; i < propertyValues->GetCount(); i++)
-	        {
-                Ptr<MgNullableProperty> mgp = (MgNullableProperty*)propertyValues->GetItem(i);
-                if (!mgp->IsNull())
-                {
-                    FdoPtr<FdoPropertyValue> fp = propVals->GetItem(mgp->GetName().c_str());
-                    MgdFeatureUtil::UpdateFdoPropertyValue(fp, mgp);
-                }
-            }
-        }
-
-        STRING sIndex;
-        MgUtil::Int32ToString(i, sIndex);
-
-        //Insert and stash the result in the property collection
-	    FdoPtr<FdoIFeatureReader> insertRes = insert->Execute();
-
-	    Ptr<MgFeatureReader> fr = new MgdFeatureReader(connWrap, insertRes);
-        Ptr<MgFeatureProperty> fp = new MgFeatureProperty(sIndex, fr);
-        ret->Add(fp);
-    }
-
-    MG_FEATURE_SERVICE_CATCH_AND_THROW_WITH_FEATURE_SOURCE(L"MgdUpdateFeaturesCommand::ExecuteInsert", resource)
-
-    return ret.Detach();
-}
-
 INT32 MgdUpdateFeaturesCommand::ExecuteUpdate(MgResourceIdentifier* resource, CREFSTRING className, MgPropertyCollection* propertyValues, CREFSTRING filter, MgTransaction* trans)
 {
     INT32 updated = 0;

Modified: trunk/MgDev/Desktop/MgDesktop/Services/Feature/Commands/UpdateFeatures.h
===================================================================
--- trunk/MgDev/Desktop/MgDesktop/Services/Feature/Commands/UpdateFeatures.h	2014-10-07 09:31:27 UTC (rev 8393)
+++ trunk/MgDev/Desktop/MgDesktop/Services/Feature/Commands/UpdateFeatures.h	2014-10-08 01:36:51 UTC (rev 8394)
@@ -42,8 +42,6 @@
 
     MgFeatureReader* ExecuteInsert(MgResourceIdentifier* resource, CREFSTRING className, MgPropertyCollection* propertyValues, MgTransaction* trans);
 
-    MgPropertyCollection* ExecuteInsert(MgResourceIdentifier* resource, CREFSTRING className, MgBatchPropertyCollection* batchPropertyValues, MgTransaction* trans);
-
     INT32 ExecuteUpdate(MgResourceIdentifier* resource, CREFSTRING className, MgPropertyCollection* propertyValues, CREFSTRING filter, MgTransaction* trans);
 
 	INT32 ExecuteDelete(MgResourceIdentifier* resource, CREFSTRING className, CREFSTRING filter, MgTransaction* trans);

Modified: trunk/MgDev/Desktop/MgDesktop/Services/Feature/RasterHelper.cpp
===================================================================
--- trunk/MgDev/Desktop/MgDesktop/Services/Feature/RasterHelper.cpp	2014-10-07 09:31:27 UTC (rev 8393)
+++ trunk/MgDev/Desktop/MgDesktop/Services/Feature/RasterHelper.cpp	2014-10-08 01:36:51 UTC (rev 8394)
@@ -71,6 +71,46 @@
                                              MgFeatureCommandCollection* commands,
                                              MgTransaction* transaction) { NOT_IMPLEMENTED(L"MgdRasterHelper::UpdateFeatures"); }
 
+MgFeatureReader* MgdRasterHelper::InsertFeatures(MgResourceIdentifier* resource, CREFSTRING className, MgPropertyCollection* propertyValues)   
+{
+    NOT_IMPLEMENTED(L"MgdRasterHelper::InsertFeatures");
+}
+
+MgFeatureReader* MgdRasterHelper::InsertFeatures(MgResourceIdentifier* resource, CREFSTRING className, MgPropertyCollection* propertyValues, MgTransaction* trans)
+{
+    NOT_IMPLEMENTED(L"MgdRasterHelper::InsertFeatures");
+}
+
+MgFeatureReader* MgdRasterHelper::InsertFeatures(MgResourceIdentifier* resource, CREFSTRING className, MgBatchPropertyCollection* batchPropertyValues)
+{
+    NOT_IMPLEMENTED(L"MgdRasterHelper::InsertFeatures");
+}
+
+MgFeatureReader* MgdRasterHelper::InsertFeatures(MgResourceIdentifier* resource, CREFSTRING className, MgBatchPropertyCollection* batchPropertyValues, MgTransaction* trans)
+{
+    NOT_IMPLEMENTED(L"MgdRasterHelper::InsertFeatures");
+}
+
+INT32 MgdRasterHelper::DeleteFeatures(MgResourceIdentifier* resource, CREFSTRING className, CREFSTRING filter)
+{
+    NOT_IMPLEMENTED(L"MgdRasterHelper::DeleteFeatures");
+}
+
+INT32 MgdRasterHelper::DeleteFeatures(MgResourceIdentifier* resource, CREFSTRING className, CREFSTRING filter, MgTransaction* trans)
+{
+    NOT_IMPLEMENTED(L"MgdRasterHelper::DeleteFeatures");
+}
+    
+INT32 MgdRasterHelper::UpdateMatchingFeatures(MgResourceIdentifier* resource, CREFSTRING className, MgPropertyCollection* propertyValues, CREFSTRING filter)
+{
+    NOT_IMPLEMENTED(L"MgdRasterHelper::UpdateMatchingFeatures");
+}
+
+INT32 MgdRasterHelper::UpdateMatchingFeatures(MgResourceIdentifier* resource, CREFSTRING className, MgPropertyCollection* propertyValues, CREFSTRING filter, MgTransaction* trans)
+{
+    NOT_IMPLEMENTED(L"MgdRasterHelper::UpdateMatchingFeatures");
+}
+
 MgFeatureReader* MgdRasterHelper::GetLockedFeatures(MgResourceIdentifier* resource,
                                            CREFSTRING className,
                                            MgFeatureQueryOptions* options) { NOT_IMPLEMENTED(L"MgdRasterHelper::GetLockedFeatures"); }

Modified: trunk/MgDev/Desktop/MgDesktop/Services/Feature/RasterHelper.h
===================================================================
--- trunk/MgDev/Desktop/MgDesktop/Services/Feature/RasterHelper.h	2014-10-07 09:31:27 UTC (rev 8393)
+++ trunk/MgDev/Desktop/MgDesktop/Services/Feature/RasterHelper.h	2014-10-08 01:36:51 UTC (rev 8394)
@@ -133,7 +133,23 @@
     virtual MgByteReader* EnumerateDataStores(CREFSTRING providerName, CREFSTRING partialConnString);
 
     virtual MgByteReader* GetSchemaMapping(CREFSTRING providerName, CREFSTRING partialConnString);
+
+    virtual MgFeatureReader* InsertFeatures(MgResourceIdentifier* resource, CREFSTRING className, MgPropertyCollection* propertyValues);
+
+    virtual MgFeatureReader* InsertFeatures(MgResourceIdentifier* resource, CREFSTRING className, MgPropertyCollection* propertyValues, MgTransaction* trans);
+
+    virtual MgFeatureReader* InsertFeatures(MgResourceIdentifier* resource, CREFSTRING className, MgBatchPropertyCollection* batchPropertyValues);
+
+    virtual MgFeatureReader* InsertFeatures(MgResourceIdentifier* resource, CREFSTRING className, MgBatchPropertyCollection* batchPropertyValues, MgTransaction* trans);
+
+    virtual INT32 DeleteFeatures(MgResourceIdentifier* resource, CREFSTRING className, CREFSTRING filter);
+
+	virtual INT32 DeleteFeatures(MgResourceIdentifier* resource, CREFSTRING className, CREFSTRING filter, MgTransaction* trans);
     
+    virtual INT32 UpdateMatchingFeatures(MgResourceIdentifier* resource, CREFSTRING className, MgPropertyCollection* propertyValues, CREFSTRING filter);
+
+    virtual INT32 UpdateMatchingFeatures(MgResourceIdentifier* resource, CREFSTRING className, MgPropertyCollection* propertyValues, CREFSTRING filter, MgTransaction* trans);
+    
 INTERNAL_API:
 
     MgdRasterHelper(MgdFeatureReader* reader);

Modified: trunk/MgDev/Desktop/MgDesktop/Services/FeatureService.cpp
===================================================================
--- trunk/MgDev/Desktop/MgDesktop/Services/FeatureService.cpp	2014-10-07 09:31:27 UTC (rev 8393)
+++ trunk/MgDev/Desktop/MgDesktop/Services/FeatureService.cpp	2014-10-08 01:36:51 UTC (rev 8394)
@@ -1057,9 +1057,9 @@
 	return reader.Detach();
 }
 
-MgPropertyCollection* MgdFeatureService::InsertFeatures(MgResourceIdentifier* resource, CREFSTRING className, MgBatchPropertyCollection* batchPropertyValues)
+MgFeatureReader* MgdFeatureService::InsertFeatures(MgResourceIdentifier* resource, CREFSTRING className, MgBatchPropertyCollection* batchPropertyValues)
 {
-    Ptr<MgPropertyCollection> ret;
+    Ptr<MgFeatureReader> ret;
     MG_LOG_OPERATION_MESSAGE(L"InsertFeatures");
 
     MG_FEATURE_SERVICE_TRY()
@@ -1077,9 +1077,29 @@
 
     MG_LOG_TRACE_ENTRY(L"MgdFeatureService::InsertFeatures()");
 
-    MgdUpdateFeaturesCommand cmd;
-    ret = cmd.ExecuteInsert(resource, className, batchPropertyValues, NULL);
+    Ptr<MgFeatureCommandCollection> commands = new MgFeatureCommandCollection();
+    Ptr<MgInsertFeatures> insertCmd = new MgInsertFeatures(className, batchPropertyValues);
+    commands->Add(insertCmd);
     
+    Ptr<MgPropertyCollection> props = UpdateFeatures(resource, commands, (MgTransaction*)NULL);
+    if (props->GetCount() == 1)
+    {
+        INT32 i = 0;
+        Ptr<MgProperty> prop = props->GetItem(i);
+        if (prop->GetPropertyType() == MgPropertyType::String) //FDO error in non-transactional mode
+        {
+            MgStringProperty* sp = static_cast<MgStringProperty*>(prop.p);
+            MgStringCollection args;
+            args.Add(sp->GetValue());
+            throw new MgFdoException(L"MgdFeatureService::InsertFeatures", __LINE__, __WFILE__, &args, L"MgFormatInnerExceptionMessage", NULL);
+        }
+        else if (prop->GetPropertyType() == MgPropertyType::Feature) //Insert result
+        {
+            MgFeatureProperty* fp = static_cast<MgFeatureProperty*>(prop.p);
+            ret = fp->GetValue();
+        }
+    }
+    
     // Successful operation
     MG_LOG_OPERATION_MESSAGE_ADD_STRING(MgResources::Success.c_str());
 
@@ -1099,9 +1119,9 @@
     return ret.Detach();
 }
 
-MgPropertyCollection* MgdFeatureService::InsertFeatures(MgResourceIdentifier* resource, CREFSTRING className, MgBatchPropertyCollection* batchPropertyValues, MgTransaction* trans)
+MgFeatureReader* MgdFeatureService::InsertFeatures(MgResourceIdentifier* resource, CREFSTRING className, MgBatchPropertyCollection* batchPropertyValues, MgTransaction* trans)
 {
-    Ptr<MgPropertyCollection> ret;
+    Ptr<MgFeatureReader> ret;
     MG_LOG_OPERATION_MESSAGE(L"InsertFeatures");
 
     MG_FEATURE_SERVICE_TRY()
@@ -1121,8 +1141,28 @@
 
     MG_LOG_TRACE_ENTRY(L"MgdFeatureService::InsertFeatures()");
 
-    MgdUpdateFeaturesCommand cmd;
-    ret = cmd.ExecuteInsert(resource, className, batchPropertyValues, trans);
+    Ptr<MgFeatureCommandCollection> commands = new MgFeatureCommandCollection();
+    Ptr<MgInsertFeatures> insertCmd = new MgInsertFeatures(className, batchPropertyValues);
+    commands->Add(insertCmd);
+    
+    Ptr<MgPropertyCollection> props = UpdateFeatures(resource, commands, trans);
+    if (props->GetCount() == 1)
+    {
+        INT32 i = 0;
+        Ptr<MgProperty> prop = props->GetItem(i);
+        if (prop->GetPropertyType() == MgPropertyType::String) //FDO error in non-transactional mode
+        {
+            MgStringProperty* sp = static_cast<MgStringProperty*>(prop.p);
+            MgStringCollection args;
+            args.Add(sp->GetValue());
+            throw new MgFdoException(L"MgdFeatureService::InsertFeatures", __LINE__, __WFILE__, &args, L"MgFormatInnerExceptionMessage", NULL);
+        }
+        else if (prop->GetPropertyType() == MgPropertyType::Feature) //Insert result
+        {
+            MgFeatureProperty* fp = static_cast<MgFeatureProperty*>(prop.p);
+            ret = fp->GetValue();
+        }
+    }
 
     // Successful operation
     MG_LOG_OPERATION_MESSAGE_ADD_STRING(MgResources::Success.c_str());
@@ -1143,14 +1183,14 @@
     return ret.Detach();
 }
 
-INT32 MgdFeatureService::UpdateFeatures(MgResourceIdentifier* resource, CREFSTRING className, MgPropertyCollection* propertyValues, CREFSTRING filter)
+INT32 MgdFeatureService::UpdateMatchingFeatures(MgResourceIdentifier* resource, CREFSTRING className, MgPropertyCollection* propertyValues, CREFSTRING filter)
 {
     INT32 ret = 0;
-    MG_LOG_OPERATION_MESSAGE(L"UpdateFeatures");
+    MG_LOG_OPERATION_MESSAGE(L"UpdateMatchingFeatures");
 
     MG_FEATURE_SERVICE_TRY()
 
-    CHECK_FEATURE_SOURCE_ARGUMENT(resource, L"MgdFeatureService::UpdateFeatures");
+    CHECK_FEATURE_SOURCE_ARGUMENT(resource, L"MgdFeatureService::UpdateMatchingFeatures");
 
     MG_LOG_OPERATION_MESSAGE_INIT(MG_API_VERSION(1, 0, 0), 4);
     MG_LOG_OPERATION_MESSAGE_PARAMETERS_START();
@@ -1163,14 +1203,14 @@
     MG_LOG_OPERATION_MESSAGE_ADD_STRING(L"STRING");
     MG_LOG_OPERATION_MESSAGE_PARAMETERS_END();
 
-    MG_LOG_TRACE_ENTRY(L"MgdFeatureService::UpdateFeatures()");
+    MG_LOG_TRACE_ENTRY(L"MgdFeatureService::UpdateMatchingFeatures()");
 
-	ret = UpdateFeatures(resource, className, propertyValues, filter, NULL);
+	ret = UpdateMatchingFeatures(resource, className, propertyValues, filter, NULL);
     
     // Successful operation
     MG_LOG_OPERATION_MESSAGE_ADD_STRING(MgResources::Success.c_str());
 
-    MG_FEATURE_SERVICE_CATCH_WITH_FEATURE_SOURCE(L"MgdFeatureService::UpdateFeatures", resource)
+    MG_FEATURE_SERVICE_CATCH_WITH_FEATURE_SOURCE(L"MgdFeatureService::UpdateMatchingFeatures", resource)
 
     if (mgException != NULL)
     {
@@ -1186,14 +1226,14 @@
     return ret;
 }
 
-INT32 MgdFeatureService::UpdateFeatures(MgResourceIdentifier* resource, CREFSTRING className, MgPropertyCollection* batchPropertyValues, CREFSTRING filter, MgTransaction* trans)
+INT32 MgdFeatureService::UpdateMatchingFeatures(MgResourceIdentifier* resource, CREFSTRING className, MgPropertyCollection* batchPropertyValues, CREFSTRING filter, MgTransaction* trans)
 {
     INT32 updated = 0;
-    MG_LOG_OPERATION_MESSAGE(L"UpdateFeatures");
+    MG_LOG_OPERATION_MESSAGE(L"UpdateMatchingFeatures");
 
     MG_FEATURE_SERVICE_TRY()
 
-    CHECK_FEATURE_SOURCE_ARGUMENT(resource, L"MgdFeatureService::UpdateFeatures");
+    CHECK_FEATURE_SOURCE_ARGUMENT(resource, L"MgdFeatureService::UpdateMatchingFeatures");
 
     MG_LOG_OPERATION_MESSAGE_INIT(MG_API_VERSION(1, 0, 0), 5);
     MG_LOG_OPERATION_MESSAGE_PARAMETERS_START();
@@ -1208,7 +1248,7 @@
     MG_LOG_OPERATION_MESSAGE_ADD_STRING(L"MgTransaction");
     MG_LOG_OPERATION_MESSAGE_PARAMETERS_END();
 
-    MG_LOG_TRACE_ENTRY(L"MgdFeatureService::UpdateFeatures()");
+    MG_LOG_TRACE_ENTRY(L"MgdFeatureService::UpdateMatchingFeatures()");
 
     MgdUpdateFeaturesCommand cmd;
     updated = cmd.ExecuteUpdate(resource, className, batchPropertyValues, filter, trans);
@@ -1216,7 +1256,7 @@
     // Successful operation
     MG_LOG_OPERATION_MESSAGE_ADD_STRING(MgResources::Success.c_str());
 
-    MG_FEATURE_SERVICE_CHECK_CONNECTION_CATCH(resource, L"MgdFeatureService::UpdateFeatures")
+    MG_FEATURE_SERVICE_CHECK_CONNECTION_CATCH(resource, L"MgdFeatureService::UpdateMatchingFeatures")
 
     if (mgException != NULL)
     {

Modified: trunk/MgDev/Desktop/MgDesktop/Services/FeatureService.h
===================================================================
--- trunk/MgDev/Desktop/MgDesktop/Services/FeatureService.h	2014-10-07 09:31:27 UTC (rev 8393)
+++ trunk/MgDev/Desktop/MgDesktop/Services/FeatureService.h	2014-10-08 01:36:51 UTC (rev 8394)
@@ -171,32 +171,31 @@
 
     virtual MgByteReader* GetSchemaMapping(CREFSTRING providerName, CREFSTRING partialConnString);
 
-    //------- Desktop API additions --------//
+    virtual MgFeatureReader* InsertFeatures(MgResourceIdentifier* resource, CREFSTRING className, MgPropertyCollection* propertyValues);
 
-    MgdScrollableFeatureReader* SelectFeaturesExtended(MgResourceIdentifier* resource,
-                                                       CREFSTRING className,
-                                                       MgFeatureQueryOptions* options);
+    virtual MgFeatureReader* InsertFeatures(MgResourceIdentifier* resource, CREFSTRING className, MgPropertyCollection* propertyValues, MgTransaction* trans);
 
-    void RegisterProvider(CREFSTRING providerLibraryPath);
+    virtual MgFeatureReader* InsertFeatures(MgResourceIdentifier* resource, CREFSTRING className, MgBatchPropertyCollection* batchPropertyValues);
 
-    void UnregisterProvider(CREFSTRING providerName);
+    virtual MgFeatureReader* InsertFeatures(MgResourceIdentifier* resource, CREFSTRING className, MgBatchPropertyCollection* batchPropertyValues, MgTransaction* trans);
 
-	MgFeatureReader* InsertFeatures(MgResourceIdentifier* resource, CREFSTRING className, MgPropertyCollection* propertyValues);
+    virtual INT32 DeleteFeatures(MgResourceIdentifier* resource, CREFSTRING className, CREFSTRING filter);
 
-    MgFeatureReader* InsertFeatures(MgResourceIdentifier* resource, CREFSTRING className, MgPropertyCollection* propertyValues, MgTransaction* trans);
+	virtual INT32 DeleteFeatures(MgResourceIdentifier* resource, CREFSTRING className, CREFSTRING filter, MgTransaction* trans);
+    
+    virtual INT32 UpdateMatchingFeatures(MgResourceIdentifier* resource, CREFSTRING className, MgPropertyCollection* propertyValues, CREFSTRING filter);
 
-    MgPropertyCollection* InsertFeatures(MgResourceIdentifier* resource, CREFSTRING className, MgBatchPropertyCollection* batchPropertyValues);
+    virtual INT32 UpdateMatchingFeatures(MgResourceIdentifier* resource, CREFSTRING className, MgPropertyCollection* propertyValues, CREFSTRING filter, MgTransaction* trans);
 
-    MgPropertyCollection* InsertFeatures(MgResourceIdentifier* resource, CREFSTRING className, MgBatchPropertyCollection* batchPropertyValues, MgTransaction* trans);
+    //------- Desktop API additions --------//
+    MgdScrollableFeatureReader* SelectFeaturesExtended(MgResourceIdentifier* resource,
+                                                       CREFSTRING className,
+                                                       MgFeatureQueryOptions* options);
 
-	INT32 UpdateFeatures(MgResourceIdentifier* resource, CREFSTRING className, MgPropertyCollection* propertyValues, CREFSTRING filter);
+    void RegisterProvider(CREFSTRING providerLibraryPath);
 
-    INT32 UpdateFeatures(MgResourceIdentifier* resource, CREFSTRING className, MgPropertyCollection* propertyValues, CREFSTRING filter, MgTransaction* trans);
+    void UnregisterProvider(CREFSTRING providerName);
 
-	INT32 DeleteFeatures(MgResourceIdentifier* resource, CREFSTRING className, CREFSTRING filter);
-
-	INT32 DeleteFeatures(MgResourceIdentifier* resource, CREFSTRING className, CREFSTRING filter, MgTransaction* trans);
-
 EXTERNAL_API:
     void PurgeCache(MgResourceIdentifier* resource);
 

Modified: trunk/MgDev/Desktop/MgDesktop/Services/ResourceService.cpp
===================================================================
--- trunk/MgDev/Desktop/MgDesktop/Services/ResourceService.cpp	2014-10-07 09:31:27 UTC (rev 8393)
+++ trunk/MgDev/Desktop/MgDesktop/Services/ResourceService.cpp	2014-10-08 01:36:51 UTC (rev 8394)
@@ -1700,6 +1700,11 @@
 	NOT_IMPLEMENTED(L"MgdResourceService::EnumerateParentMapDefinitions");
 }
 
+MgSerializableCollection* MgdResourceService::EnumerateParentTileSetDefinitions(MgSerializableCollection* resources)
+{
+    NOT_IMPLEMENTED(L"MgdResourceService::EnumerateParentTileSetDefinitions");
+}
+
 void MgdResourceService::DeleteSessionFiles()
 {
     Ptr<MgStringCollection> dirs = new MgStringCollection();

Modified: trunk/MgDev/Desktop/MgDesktop/Services/ResourceService.h
===================================================================
--- trunk/MgDev/Desktop/MgDesktop/Services/ResourceService.h	2014-10-07 09:31:27 UTC (rev 8393)
+++ trunk/MgDev/Desktop/MgDesktop/Services/ResourceService.h	2014-10-08 01:36:51 UTC (rev 8394)
@@ -86,6 +86,8 @@
 
     virtual MgSerializableCollection* EnumerateParentMapDefinitions(MgSerializableCollection* resources);
 
+    virtual MgSerializableCollection* EnumerateParentTileSetDefinitions(MgSerializableCollection* resources);
+
     STRING GetContentDirectory(MgResourceIdentifier* resId);
 	STRING ResolveContentPath(MgResourceIdentifier* resId);
 	STRING ResolveDataPath(MgResourceIdentifier* resId);

Modified: trunk/MgDev/Desktop/Samples/SampleExtension/ModifyingMapsAndLayers.cs
===================================================================
--- trunk/MgDev/Desktop/Samples/SampleExtension/ModifyingMapsAndLayers.cs	2014-10-07 09:31:27 UTC (rev 8393)
+++ trunk/MgDev/Desktop/Samples/SampleExtension/ModifyingMapsAndLayers.cs	2014-10-08 01:36:51 UTC (rev 8394)
@@ -431,16 +431,8 @@
             */
 
             // Here's the mg-desktop way
-            MgPropertyCollection insertResult = featureService.InsertFeatures(resourceIdentifier, "Points", batchPropertyCollection);
-            for (int i = 0; i < insertResult.GetCount(); i++)
-            {
-                MgFeatureProperty fp = insertResult.GetItem(i) as MgFeatureProperty;
-                if (fp != null)
-                {
-                    MgFeatureReader fr = fp.GetValue();
-                    fr.Close();
-                }
-            }
+            MgFeatureReader insertResult = featureService.InsertFeatures(resourceIdentifier, "Points", batchPropertyCollection);
+            insertResult.Close();
 
             // ...
             //---------------------------------------------------//

Modified: trunk/MgDev/Desktop/UnitTest/TestFeatureService.cpp
===================================================================
--- trunk/MgDev/Desktop/UnitTest/TestFeatureService.cpp	2014-10-07 09:31:27 UTC (rev 8393)
+++ trunk/MgDev/Desktop/UnitTest/TestFeatureService.cpp	2014-10-08 01:36:51 UTC (rev 8394)
@@ -1719,20 +1719,15 @@
         batch->Add(propVals);
 
         //Call the API
-        Ptr<MgPropertyCollection> insertRes = pService->InsertFeatures(fsId, L"Default:Parcels", batch);
+        Ptr<MgFeatureReader> insertRes = pService->InsertFeatures(fsId, L"Default:Parcels", batch);
         
-        //We inserted 3 features
-        CPPUNIT_ASSERT(3 == insertRes->GetCount());
-
-        for (INT32 i = 0; i < insertRes->GetCount(); i++)
+        INT32 insertedCount = 0;
+        while (insertRes->ReadNext())
         {
-            Ptr<MgProperty> res = insertRes->GetItem(i);
-            CPPUNIT_ASSERT(MgPropertyType::Feature == res->GetPropertyType());
-
-            MgFeatureProperty* fp = static_cast<MgFeatureProperty*>(res.p);
-            Ptr<MgFeatureReader> fr = fp->GetValue();
-            fr->Close();
+            insertedCount++;
         }
+        //We inserted 3 features
+        CPPUNIT_ASSERT(3 == insertedCount);
 
         //Now query to verify all values are the same
         Ptr<MgFeatureReader> reader = pService->SelectFeatures(fsId, L"Default:Parcels", NULL);
@@ -1837,7 +1832,7 @@
         ACE_OS::itoa(smTestSdfId, sdfNum, 10);
         filter += sdfNum;
 
-        int updated = pService->UpdateFeatures(fsId, className, propVals, filter);
+        int updated = pService->UpdateMatchingFeatures(fsId, className, propVals, filter);
         CPPUNIT_ASSERT(updated == 1);
 
         Ptr<MgFeatureQueryOptions> query = new MgFeatureQueryOptions();
@@ -3429,7 +3424,7 @@
         ACE_OS::itoa(smTestSdfId, sdfNum, 10);
         filter += sdfNum;
 
-        int updated = parcels->UpdateFeatures(propVals, filter);
+        int updated = parcels->UpdateMatchingFeatures(propVals, filter);
         CPPUNIT_ASSERT(updated == 1);
 
         Ptr<MgFeatureQueryOptions> query = new MgFeatureQueryOptions();

Modified: trunk/MgDev/Server/src/Services/Feature/FeatureOperationFactory.cpp
===================================================================
--- trunk/MgDev/Server/src/Services/Feature/FeatureOperationFactory.cpp	2014-10-07 09:31:27 UTC (rev 8393)
+++ trunk/MgDev/Server/src/Services/Feature/FeatureOperationFactory.cpp	2014-10-08 01:36:51 UTC (rev 8394)
@@ -36,6 +36,10 @@
 #include "OpTestConnection.h"
 #include "OpTestFeatureSourceConnection.h"
 #include "OpUpdateFeatures.h"
+#include "OpInsertFeatures.h"
+#include "OpInsertFeaturesBatched.h"
+#include "OpUpdateMatchingFeatures.h"
+#include "OpDeleteFeatures.h"
 #include "OpGetFeatures.h"
 #include "OpCloseFeatureReader.h"
 #include "OpGetLongTransactions.h"
@@ -236,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))
         {
@@ -332,6 +348,54 @@
         }
         break;
 
+    case MgFeatureServiceOpId::InsertFeatures:
+        switch (VERSION_NO_PHASE(operationVersion))
+        {
+        case VERSION_SUPPORTED(3,0):
+            handler.reset(new MgOpInsertFeatures());
+            break;
+        default:
+            throw new MgInvalidOperationVersionException(
+                L"MgFeatureOperationFactory.GetOperation", __LINE__, __WFILE__, NULL, L"", NULL);
+        }
+        break;
+
+    case MgFeatureServiceOpId::InsertFeatures2:
+        switch (VERSION_NO_PHASE(operationVersion))
+        {
+        case VERSION_SUPPORTED(3,0):
+            handler.reset(new MgOpInsertFeaturesBatched());
+            break;
+        default:
+            throw new MgInvalidOperationVersionException(
+                L"MgFeatureOperationFactory.GetOperation", __LINE__, __WFILE__, NULL, L"", NULL);
+        }
+        break;
+
+    case MgFeatureServiceOpId::UpdateMatchingFeatures:
+        switch (VERSION_NO_PHASE(operationVersion))
+        {
+        case VERSION_SUPPORTED(3,0):
+            handler.reset(new MgOpUpdateMatchingFeatures());
+            break;
+        default:
+            throw new MgInvalidOperationVersionException(
+                L"MgFeatureOperationFactory.GetOperation", __LINE__, __WFILE__, NULL, L"", NULL);
+        }
+        break;
+
+    case MgFeatureServiceOpId::DeleteFeatures:
+        switch (VERSION_NO_PHASE(operationVersion))
+        {
+        case VERSION_SUPPORTED(3,0):
+            handler.reset(new MgOpDeleteFeatures());
+            break;
+        default:
+            throw new MgInvalidOperationVersionException(
+                L"MgFeatureOperationFactory.GetOperation", __LINE__, __WFILE__, NULL, L"", NULL);
+        }
+        break;
+
     case MgFeatureServiceOpId::GetFeatures_Id:
         switch (VERSION_NO_PHASE(operationVersion))
         {

Copied: trunk/MgDev/Server/src/Services/Feature/OpDeleteFeatures.cpp (from rev 8268, sandbox/jng/convenience_apis/Server/src/Services/Feature/OpDeleteFeatures.cpp)
===================================================================
--- trunk/MgDev/Server/src/Services/Feature/OpDeleteFeatures.cpp	                        (rev 0)
+++ trunk/MgDev/Server/src/Services/Feature/OpDeleteFeatures.cpp	2014-10-08 01:36:51 UTC (rev 8394)
@@ -0,0 +1,150 @@
+//
+//  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 "OpDeleteFeatures.h"
+#include "ServerFeatureTransactionPool.h"
+
+///----------------------------------------------------------------------------
+/// <summary>
+/// Constructs the object.
+/// </summary>
+///----------------------------------------------------------------------------
+MgOpDeleteFeatures::MgOpDeleteFeatures()
+{
+}
+
+
+///----------------------------------------------------------------------------
+/// <summary>
+/// Destructs the object.
+/// </summary>
+///----------------------------------------------------------------------------
+MgOpDeleteFeatures::~MgOpDeleteFeatures()
+{
+}
+
+
+///----------------------------------------------------------------------------
+/// <summary>
+/// Executes the operation.
+/// </summary>
+///
+/// <exceptions>
+/// MgException
+/// </exceptions>
+///----------------------------------------------------------------------------
+void MgOpDeleteFeatures::Execute()
+{
+    ACE_DEBUG((LM_DEBUG, ACE_TEXT("  (%t) MgOpDeleteFeatures::Execute()\n")));
+
+    MG_LOG_OPERATION_MESSAGE(L"DeleteFeatures");
+
+    MG_FEATURE_SERVICE_TRY()
+
+    MG_LOG_OPERATION_MESSAGE_INIT(m_packet.m_OperationVersion, m_packet.m_NumArguments);
+
+    ACE_ASSERT(m_stream != NULL);
+
+    if (3 == m_packet.m_NumArguments)
+    {
+        Ptr<MgResourceIdentifier> resource = (MgResourceIdentifier*)m_stream->GetObject();
+        STRING className;
+        m_stream->GetString(className);
+        STRING filter;
+        m_stream->GetString(filter);
+        
+        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(filter.c_str());
+        MG_LOG_OPERATION_MESSAGE_PARAMETERS_END();
+
+        Validate();
+
+        // Execute the operation
+        INT32 result = m_service->DeleteFeatures(resource, className, filter);
+
+        // Write the response
+        EndExecution(result);
+    }
+    if (4 == m_packet.m_NumArguments)
+    {
+        Ptr<MgResourceIdentifier> resource = (MgResourceIdentifier*)m_stream->GetObject();
+        STRING className;
+        m_stream->GetString(className);
+        STRING filter;
+        m_stream->GetString(filter);
+        STRING transactionId;
+        m_stream->GetString(transactionId);
+        
+        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(filter.c_str());
+        MG_LOG_OPERATION_MESSAGE_PARAMETERS_END();
+
+        Validate();
+
+        MgServerFeatureTransactionPool* transactionPool = MgServerFeatureTransactionPool::GetInstance();
+        CHECKNULL(transactionPool, L"MgOpDeleteFeatures.Execute")
+
+        transactionPool->ValidateTimeout(transactionId);
+
+        // Get the MgTransaction instance from the pool if one has been started for this resource.
+        Ptr<MgServerFeatureTransaction> transaction = transactionPool->GetTransaction(transactionId);
+
+        // Execute the operation
+        INT32 result = m_service->DeleteFeatures(resource, className, filter, (MgTransaction*)transaction.p);
+
+        // Write the response
+        EndExecution(result);
+    }
+    else
+    {
+        MG_LOG_OPERATION_MESSAGE_PARAMETERS_START();
+        MG_LOG_OPERATION_MESSAGE_PARAMETERS_END();
+    }
+
+    if (!m_argsRead)
+    {
+        throw new MgOperationProcessingException(L"MgOpDeleteFeatures.Execute",
+            __LINE__, __WFILE__, NULL, L"", NULL);
+    }
+
+    // Successful operation
+    MG_LOG_OPERATION_MESSAGE_ADD_STRING(MgResources::Success.c_str());
+
+    MG_FEATURE_SERVICE_CATCH(L"MgOpDeleteFeatures.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/OpDeleteFeatures.h (from rev 8268, sandbox/jng/convenience_apis/Server/src/Services/Feature/OpDeleteFeatures.h)
===================================================================
--- trunk/MgDev/Server/src/Services/Feature/OpDeleteFeatures.h	                        (rev 0)
+++ trunk/MgDev/Server/src/Services/Feature/OpDeleteFeatures.h	2014-10-08 01:36:51 UTC (rev 8394)
@@ -0,0 +1,33 @@
+//
+//  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_OP_DELETE_FEATURES_H
+#define MG_OP_DELETE_FEATURES_H
+
+#include "FeatureOperation.h"
+
+class MgOpDeleteFeatures : public MgFeatureOperation
+{
+    public:
+        MgOpDeleteFeatures();
+        virtual ~MgOpDeleteFeatures();
+
+    public:
+        virtual void Execute();
+};
+
+#endif

Copied: trunk/MgDev/Server/src/Services/Feature/OpInsertFeatures.cpp (from rev 8268, sandbox/jng/convenience_apis/Server/src/Services/Feature/OpInsertFeatures.cpp)
===================================================================
--- trunk/MgDev/Server/src/Services/Feature/OpInsertFeatures.cpp	                        (rev 0)
+++ trunk/MgDev/Server/src/Services/Feature/OpInsertFeatures.cpp	2014-10-08 01:36:51 UTC (rev 8394)
@@ -0,0 +1,150 @@
+//
+//  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 "OpInsertFeatures.h"
+#include "ServerFeatureTransactionPool.h"
+
+///----------------------------------------------------------------------------
+/// <summary>
+/// Constructs the object.
+/// </summary>
+///----------------------------------------------------------------------------
+MgOpInsertFeatures::MgOpInsertFeatures()
+{
+}
+
+
+///----------------------------------------------------------------------------
+/// <summary>
+/// Destructs the object.
+/// </summary>
+///----------------------------------------------------------------------------
+MgOpInsertFeatures::~MgOpInsertFeatures()
+{
+}
+
+
+///----------------------------------------------------------------------------
+/// <summary>
+/// Executes the operation.
+/// </summary>
+///
+/// <exceptions>
+/// MgException
+/// </exceptions>
+///----------------------------------------------------------------------------
+void MgOpInsertFeatures::Execute()
+{
+    ACE_DEBUG((LM_DEBUG, ACE_TEXT("  (%t) MgOpInsertFeatures::Execute()\n")));
+
+    MG_LOG_OPERATION_MESSAGE(L"InsertFeatures");
+
+    MG_FEATURE_SERVICE_TRY()
+
+    MG_LOG_OPERATION_MESSAGE_INIT(m_packet.m_OperationVersion, m_packet.m_NumArguments);
+
+    ACE_ASSERT(m_stream != NULL);
+
+    if (3 == m_packet.m_NumArguments)
+    {
+        Ptr<MgResourceIdentifier> resource = (MgResourceIdentifier*)m_stream->GetObject();
+        STRING className;
+        m_stream->GetString(className);
+        Ptr<MgPropertyCollection> properties = (MgPropertyCollection*)m_stream->GetObject();
+        
+        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"MgPropertyCollection");
+        MG_LOG_OPERATION_MESSAGE_PARAMETERS_END();
+
+        Validate();
+
+        // Execute the operation
+        Ptr<MgFeatureReader> result = m_service->InsertFeatures(resource, className, properties);
+
+        // Write the response
+        EndExecution(result);
+    }
+    if (4 == m_packet.m_NumArguments)
+    {
+        Ptr<MgResourceIdentifier> resource = (MgResourceIdentifier*)m_stream->GetObject();
+        STRING className;
+        m_stream->GetString(className);
+        Ptr<MgPropertyCollection> properties = (MgPropertyCollection*)m_stream->GetObject();
+        STRING transactionId;
+        m_stream->GetString(transactionId);
+        
+        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"MgPropertyCollection");
+        MG_LOG_OPERATION_MESSAGE_ADD_SEPARATOR();
+        MG_LOG_OPERATION_MESSAGE_ADD_STRING(transactionId.c_str());
+        MG_LOG_OPERATION_MESSAGE_PARAMETERS_END();
+
+        Validate();
+
+        MgServerFeatureTransactionPool* transactionPool = MgServerFeatureTransactionPool::GetInstance();
+        CHECKNULL(transactionPool, L"MgOpInsertFeatures.Execute")
+
+        transactionPool->ValidateTimeout(transactionId);
+
+        // Get the MgTransaction instance from the pool if one has been started for this resource.
+        Ptr<MgServerFeatureTransaction> transaction = transactionPool->GetTransaction(transactionId);
+
+        // Execute the operation
+        Ptr<MgFeatureReader> result = m_service->InsertFeatures(resource, className, properties, (MgTransaction*)transaction.p);
+
+        // Write the response
+        EndExecution(result);
+    }
+    else
+    {
+        MG_LOG_OPERATION_MESSAGE_PARAMETERS_START();
+        MG_LOG_OPERATION_MESSAGE_PARAMETERS_END();
+    }
+
+    if (!m_argsRead)
+    {
+        throw new MgOperationProcessingException(L"MgOpInsertFeatures.Execute",
+            __LINE__, __WFILE__, NULL, L"", NULL);
+    }
+
+    // Successful operation
+    MG_LOG_OPERATION_MESSAGE_ADD_STRING(MgResources::Success.c_str());
+
+    MG_FEATURE_SERVICE_CATCH(L"MgOpInsertFeatures.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/OpInsertFeatures.h (from rev 8268, sandbox/jng/convenience_apis/Server/src/Services/Feature/OpInsertFeatures.h)
===================================================================
--- trunk/MgDev/Server/src/Services/Feature/OpInsertFeatures.h	                        (rev 0)
+++ trunk/MgDev/Server/src/Services/Feature/OpInsertFeatures.h	2014-10-08 01:36:51 UTC (rev 8394)
@@ -0,0 +1,33 @@
+//
+//  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_OP_INSERT_FEATURES_H
+#define MG_OP_INSERT_FEATURES_H
+
+#include "FeatureOperation.h"
+
+class MgOpInsertFeatures : public MgFeatureOperation
+{
+    public:
+        MgOpInsertFeatures();
+        virtual ~MgOpInsertFeatures();
+
+    public:
+        virtual void Execute();
+};
+
+#endif

Copied: trunk/MgDev/Server/src/Services/Feature/OpInsertFeaturesBatched.cpp (from rev 8268, sandbox/jng/convenience_apis/Server/src/Services/Feature/OpInsertFeaturesBatched.cpp)
===================================================================
--- trunk/MgDev/Server/src/Services/Feature/OpInsertFeaturesBatched.cpp	                        (rev 0)
+++ trunk/MgDev/Server/src/Services/Feature/OpInsertFeaturesBatched.cpp	2014-10-08 01:36:51 UTC (rev 8394)
@@ -0,0 +1,150 @@
+//
+//  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 "OpInsertFeaturesBatched.h"
+#include "ServerFeatureTransactionPool.h"
+
+///----------------------------------------------------------------------------
+/// <summary>
+/// Constructs the object.
+/// </summary>
+///----------------------------------------------------------------------------
+MgOpInsertFeaturesBatched::MgOpInsertFeaturesBatched()
+{
+}
+
+
+///----------------------------------------------------------------------------
+/// <summary>
+/// Destructs the object.
+/// </summary>
+///----------------------------------------------------------------------------
+MgOpInsertFeaturesBatched::~MgOpInsertFeaturesBatched()
+{
+}
+
+
+///----------------------------------------------------------------------------
+/// <summary>
+/// Executes the operation.
+/// </summary>
+///
+/// <exceptions>
+/// MgException
+/// </exceptions>
+///----------------------------------------------------------------------------
+void MgOpInsertFeaturesBatched::Execute()
+{
+    ACE_DEBUG((LM_DEBUG, ACE_TEXT("  (%t) MgOpInsertFeaturesBatched::Execute()\n")));
+
+    MG_LOG_OPERATION_MESSAGE(L"InsertFeaturesBatched");
+
+    MG_FEATURE_SERVICE_TRY()
+
+    MG_LOG_OPERATION_MESSAGE_INIT(m_packet.m_OperationVersion, m_packet.m_NumArguments);
+
+    ACE_ASSERT(m_stream != NULL);
+
+    if (3 == m_packet.m_NumArguments)
+    {
+        Ptr<MgResourceIdentifier> resource = (MgResourceIdentifier*)m_stream->GetObject();
+        STRING className;
+        m_stream->GetString(className);
+        Ptr<MgBatchPropertyCollection> properties = (MgBatchPropertyCollection*)m_stream->GetObject();
+        
+        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"MgPropertyCollection");
+        MG_LOG_OPERATION_MESSAGE_PARAMETERS_END();
+
+        Validate();
+
+        // Execute the operation
+        Ptr<MgFeatureReader> result = m_service->InsertFeatures(resource, className, properties);
+
+        // Write the response
+        EndExecution(result);
+    }
+    if (4 == m_packet.m_NumArguments)
+    {
+        Ptr<MgResourceIdentifier> resource = (MgResourceIdentifier*)m_stream->GetObject();
+        STRING className;
+        m_stream->GetString(className);
+        Ptr<MgBatchPropertyCollection> properties = (MgBatchPropertyCollection*)m_stream->GetObject();
+        STRING transactionId;
+        m_stream->GetString(transactionId);
+        
+        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"MgPropertyCollection");
+        MG_LOG_OPERATION_MESSAGE_ADD_SEPARATOR();
+        MG_LOG_OPERATION_MESSAGE_ADD_STRING(transactionId.c_str());
+        MG_LOG_OPERATION_MESSAGE_PARAMETERS_END();
+
+        Validate();
+
+        MgServerFeatureTransactionPool* transactionPool = MgServerFeatureTransactionPool::GetInstance();
+        CHECKNULL(transactionPool, L"MgOpInsertFeaturesBatched.Execute")
+
+        transactionPool->ValidateTimeout(transactionId);
+
+        // Get the MgTransaction instance from the pool if one has been started for this resource.
+        Ptr<MgServerFeatureTransaction> transaction = transactionPool->GetTransaction(transactionId);
+
+        // Execute the operation
+        Ptr<MgFeatureReader> result = m_service->InsertFeatures(resource, className, properties, (MgTransaction*)transaction.p);
+
+        // Write the response
+        EndExecution(result);
+    }
+    else
+    {
+        MG_LOG_OPERATION_MESSAGE_PARAMETERS_START();
+        MG_LOG_OPERATION_MESSAGE_PARAMETERS_END();
+    }
+
+    if (!m_argsRead)
+    {
+        throw new MgOperationProcessingException(L"MgOpInsertFeaturesBatched.Execute",
+            __LINE__, __WFILE__, NULL, L"", NULL);
+    }
+
+    // Successful operation
+    MG_LOG_OPERATION_MESSAGE_ADD_STRING(MgResources::Success.c_str());
+
+    MG_FEATURE_SERVICE_CATCH(L"MgOpInsertFeaturesBatched.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/OpInsertFeaturesBatched.h (from rev 8268, sandbox/jng/convenience_apis/Server/src/Services/Feature/OpInsertFeaturesBatched.h)
===================================================================
--- trunk/MgDev/Server/src/Services/Feature/OpInsertFeaturesBatched.h	                        (rev 0)
+++ trunk/MgDev/Server/src/Services/Feature/OpInsertFeaturesBatched.h	2014-10-08 01:36:51 UTC (rev 8394)
@@ -0,0 +1,33 @@
+//
+//  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_OP_INSERT_FEATURES_BATCHED_H
+#define MG_OP_INSERT_FEATURES_BATCHED_H
+
+#include "FeatureOperation.h"
+
+class MgOpInsertFeaturesBatched : public MgFeatureOperation
+{
+    public:
+        MgOpInsertFeaturesBatched();
+        virtual ~MgOpInsertFeaturesBatched();
+
+    public:
+        virtual void Execute();
+};
+
+#endif

Modified: trunk/MgDev/Server/src/Services/Feature/OpSelectFeatures.cpp
===================================================================
--- trunk/MgDev/Server/src/Services/Feature/OpSelectFeatures.cpp	2014-10-07 09:31:27 UTC (rev 8393)
+++ trunk/MgDev/Server/src/Services/Feature/OpSelectFeatures.cpp	2014-10-08 01:36:51 UTC (rev 8394)
@@ -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();

Copied: trunk/MgDev/Server/src/Services/Feature/OpUpdateMatchingFeatures.cpp (from rev 8268, sandbox/jng/convenience_apis/Server/src/Services/Feature/OpUpdateMatchingFeatures.cpp)
===================================================================
--- trunk/MgDev/Server/src/Services/Feature/OpUpdateMatchingFeatures.cpp	                        (rev 0)
+++ trunk/MgDev/Server/src/Services/Feature/OpUpdateMatchingFeatures.cpp	2014-10-08 01:36:51 UTC (rev 8394)
@@ -0,0 +1,158 @@
+//
+//  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 "OpUpdateMatchingFeatures.h"
+#include "ServerFeatureTransactionPool.h"
+
+///----------------------------------------------------------------------------
+/// <summary>
+/// Constructs the object.
+/// </summary>
+///----------------------------------------------------------------------------
+MgOpUpdateMatchingFeatures::MgOpUpdateMatchingFeatures()
+{
+}
+
+
+///----------------------------------------------------------------------------
+/// <summary>
+/// Destructs the object.
+/// </summary>
+///----------------------------------------------------------------------------
+MgOpUpdateMatchingFeatures::~MgOpUpdateMatchingFeatures()
+{
+}
+
+
+///----------------------------------------------------------------------------
+/// <summary>
+/// Executes the operation.
+/// </summary>
+///
+/// <exceptions>
+/// MgException
+/// </exceptions>
+///----------------------------------------------------------------------------
+void MgOpUpdateMatchingFeatures::Execute()
+{
+    ACE_DEBUG((LM_DEBUG, ACE_TEXT("  (%t) MgOpUpdateMatchingFeatures::Execute()\n")));
+
+    MG_LOG_OPERATION_MESSAGE(L"UpdateMatchingFeatures");
+
+    MG_FEATURE_SERVICE_TRY()
+
+    MG_LOG_OPERATION_MESSAGE_INIT(m_packet.m_OperationVersion, m_packet.m_NumArguments);
+
+    ACE_ASSERT(m_stream != NULL);
+
+    if (4 == m_packet.m_NumArguments)
+    {
+        Ptr<MgResourceIdentifier> resource = (MgResourceIdentifier*)m_stream->GetObject();
+        STRING className;
+        m_stream->GetString(className);
+        Ptr<MgPropertyCollection> properties = (MgPropertyCollection*)m_stream->GetObject();
+        STRING filter;
+        m_stream->GetString(filter);
+        
+        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"MgPropertyCollection");
+        MG_LOG_OPERATION_MESSAGE_ADD_SEPARATOR();
+        MG_LOG_OPERATION_MESSAGE_ADD_STRING(filter.c_str());
+        MG_LOG_OPERATION_MESSAGE_PARAMETERS_END();
+
+        Validate();
+
+        // Execute the operation
+        INT32 result = m_service->UpdateMatchingFeatures(resource, className, properties, filter);
+
+        // Write the response
+        EndExecution(result);
+    }
+    if (5 == m_packet.m_NumArguments)
+    {
+        Ptr<MgResourceIdentifier> resource = (MgResourceIdentifier*)m_stream->GetObject();
+        STRING className;
+        m_stream->GetString(className);
+        Ptr<MgPropertyCollection> properties = (MgPropertyCollection*)m_stream->GetObject();
+        STRING filter;
+        m_stream->GetString(filter);
+        STRING transactionId;
+        m_stream->GetString(transactionId);
+        
+        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"MgPropertyCollection");
+        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(transactionId.c_str());
+        MG_LOG_OPERATION_MESSAGE_PARAMETERS_END();
+
+        Validate();
+
+        MgServerFeatureTransactionPool* transactionPool = MgServerFeatureTransactionPool::GetInstance();
+        CHECKNULL(transactionPool, L"MgOpUpdateMatchingFeatures.Execute")
+
+        transactionPool->ValidateTimeout(transactionId);
+
+        // Get the MgTransaction instance from the pool if one has been started for this resource.
+        Ptr<MgServerFeatureTransaction> transaction = transactionPool->GetTransaction(transactionId);
+
+        // Execute the operation
+        INT32 result = m_service->UpdateMatchingFeatures(resource, className, properties, filter, (MgTransaction*)transaction.p);
+
+        // Write the response
+        EndExecution(result);
+    }
+    else
+    {
+        MG_LOG_OPERATION_MESSAGE_PARAMETERS_START();
+        MG_LOG_OPERATION_MESSAGE_PARAMETERS_END();
+    }
+
+    if (!m_argsRead)
+    {
+        throw new MgOperationProcessingException(L"MgOpUpdateMatchingFeatures.Execute",
+            __LINE__, __WFILE__, NULL, L"", NULL);
+    }
+
+    // Successful operation
+    MG_LOG_OPERATION_MESSAGE_ADD_STRING(MgResources::Success.c_str());
+
+    MG_FEATURE_SERVICE_CATCH(L"MgOpUpdateMatchingFeatures.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/OpUpdateMatchingFeatures.h (from rev 8268, sandbox/jng/convenience_apis/Server/src/Services/Feature/OpUpdateMatchingFeatures.h)
===================================================================
--- trunk/MgDev/Server/src/Services/Feature/OpUpdateMatchingFeatures.h	                        (rev 0)
+++ trunk/MgDev/Server/src/Services/Feature/OpUpdateMatchingFeatures.h	2014-10-08 01:36:51 UTC (rev 8394)
@@ -0,0 +1,33 @@
+//
+//  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_OP_UPDATE_MATCHING_FEATURES_H
+#define MG_OP_UPDATE_MATCHING_FEATURES_H
+
+#include "FeatureOperation.h"
+
+class MgOpUpdateMatchingFeatures : public MgFeatureOperation
+{
+    public:
+        MgOpUpdateMatchingFeatures();
+        virtual ~MgOpUpdateMatchingFeatures();
+
+    public:
+        virtual void Execute();
+};
+
+#endif

Modified: trunk/MgDev/Server/src/Services/Feature/ServerFeatureService.cpp
===================================================================
--- trunk/MgDev/Server/src/Services/Feature/ServerFeatureService.cpp	2014-10-07 09:31:27 UTC (rev 8393)
+++ trunk/MgDev/Server/src/Services/Feature/ServerFeatureService.cpp	2014-10-08 01:36:51 UTC (rev 8394)
@@ -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();
 }
 
 
@@ -637,7 +673,308 @@
     return asuf.Execute(resource, commands, transaction);
 }
 
+MgFeatureReader* MgServerFeatureService::InsertFeatures(MgResourceIdentifier* resource,
+                                                        CREFSTRING className,
+                                                        MgPropertyCollection* propertyValues)
+{
+    MG_LOG_TRACE_ENTRY(L"MgServerFeatureService::InsertFeatures()");
 
+    Ptr<MgFeatureReader> ret;
+    MG_FEATURE_SERVICE_TRY()
+    
+    Ptr<MgInsertFeatures> insert = new MgInsertFeatures(className, propertyValues);
+    Ptr<MgFeatureCommandCollection> cmds = new MgFeatureCommandCollection();
+    cmds->Add(insert);
+    MgServerUpdateFeatures asuf;
+    Ptr<MgPropertyCollection> props = asuf.Execute(resource, cmds, false);
+
+    if (props->GetCount() == 1)
+    {
+        INT32 i = 0;
+        Ptr<MgProperty> prop = props->GetItem(i);
+        if (prop->GetPropertyType() == MgPropertyType::String) //FDO error in non-transactional mode
+        {
+            MgStringProperty* sp = static_cast<MgStringProperty*>(prop.p);
+            MgStringCollection args;
+            args.Add(sp->GetValue());
+            throw new MgFdoException(L"MgServerFeatureService.InsertFeatures", __LINE__, __WFILE__, &args, L"MgFormatInnerExceptionMessage", NULL);
+        }
+        else if (prop->GetPropertyType() == MgPropertyType::Feature) //Insert result
+        {
+            MgFeatureProperty* fp = static_cast<MgFeatureProperty*>(prop.p);
+            ret = fp->GetValue();
+        }
+    }
+
+    MG_FEATURE_SERVICE_CATCH_AND_THROW_WITH_FEATURE_SOURCE(L"MgServerFeatureService.InsertFeatures", resource)
+    return ret.Detach();
+}
+
+MgFeatureReader* MgServerFeatureService::InsertFeatures(MgResourceIdentifier* resource,
+                                                        CREFSTRING className,
+                                                        MgPropertyCollection* propertyValues,
+                                                        MgTransaction* trans)
+{
+    MG_LOG_TRACE_ENTRY(L"MgServerFeatureService::InsertFeatures()");
+
+    Ptr<MgFeatureReader> ret;
+    MG_FEATURE_SERVICE_TRY()
+    
+    Ptr<MgInsertFeatures> insert = new MgInsertFeatures(className, propertyValues);
+    Ptr<MgFeatureCommandCollection> cmds = new MgFeatureCommandCollection();
+    cmds->Add(insert);
+    MgServerUpdateFeatures asuf;
+    Ptr<MgPropertyCollection> props = asuf.Execute(resource, cmds, trans);
+
+    if (cmds->GetCount() == 1)
+    {
+        INT32 i = 0;
+        Ptr<MgProperty> prop = props->GetItem(i);
+        if (prop->GetPropertyType() == MgPropertyType::String) //FDO error in non-transactional mode
+        {
+            MgStringProperty* sp = static_cast<MgStringProperty*>(prop.p);
+            MgStringCollection args;
+            args.Add(sp->GetValue());
+            throw new MgFdoException(L"MgServerFeatureService.InsertFeatures", __LINE__, __WFILE__, &args, L"MgFormatInnerExceptionMessage", NULL);
+        }
+        else if (prop->GetPropertyType() == MgPropertyType::Feature) //Insert result
+        {
+            MgFeatureProperty* fp = static_cast<MgFeatureProperty*>(prop.p);
+            ret = fp->GetValue();
+        }
+    }
+
+    MG_FEATURE_SERVICE_CATCH_AND_THROW_WITH_FEATURE_SOURCE(L"MgServerFeatureService.InsertFeatures", resource)
+    return ret.Detach();
+}
+
+MgFeatureReader* MgServerFeatureService::InsertFeatures(MgResourceIdentifier* resource,
+                                                        CREFSTRING className,
+                                                        MgBatchPropertyCollection* batchPropertyValues)
+{
+    MG_LOG_TRACE_ENTRY(L"MgServerFeatureService::InsertFeatures()");
+
+    Ptr<MgFeatureReader> ret;
+    MG_FEATURE_SERVICE_TRY()
+    
+    Ptr<MgInsertFeatures> insert = new MgInsertFeatures(className, batchPropertyValues);
+    Ptr<MgFeatureCommandCollection> cmds = new MgFeatureCommandCollection();
+    cmds->Add(insert);
+    MgServerUpdateFeatures asuf;
+    Ptr<MgPropertyCollection> props = asuf.Execute(resource, cmds, false);
+
+    if (cmds->GetCount() == 1)
+    {
+        INT32 i = 0;
+        Ptr<MgProperty> prop = props->GetItem(i);
+        if (prop->GetPropertyType() == MgPropertyType::String) //FDO error in non-transactional mode
+        {
+            MgStringProperty* sp = static_cast<MgStringProperty*>(prop.p);
+            MgStringCollection args;
+            args.Add(sp->GetValue());
+            throw new MgFdoException(L"MgServerFeatureService.InsertFeatures", __LINE__, __WFILE__, &args, L"MgFormatInnerExceptionMessage", NULL);
+        }
+        else if (prop->GetPropertyType() == MgPropertyType::Feature) //Insert result
+        {
+            MgFeatureProperty* fp = static_cast<MgFeatureProperty*>(prop.p);
+            ret = fp->GetValue();
+        }
+    }
+
+    MG_FEATURE_SERVICE_CATCH_AND_THROW_WITH_FEATURE_SOURCE(L"MgServerFeatureService.InsertFeatures", resource)
+    return ret.Detach();
+}
+
+MgFeatureReader* MgServerFeatureService::InsertFeatures(MgResourceIdentifier* resource,
+                                                        CREFSTRING className,
+                                                        MgBatchPropertyCollection* batchPropertyValues,
+                                                        MgTransaction* trans)
+{
+    MG_LOG_TRACE_ENTRY(L"MgServerFeatureService::InsertFeatures()");
+
+    Ptr<MgFeatureReader> ret;
+    MG_FEATURE_SERVICE_TRY()
+    
+    Ptr<MgInsertFeatures> insert = new MgInsertFeatures(className, batchPropertyValues);
+    Ptr<MgFeatureCommandCollection> cmds = new MgFeatureCommandCollection();
+    cmds->Add(insert);
+    MgServerUpdateFeatures asuf;
+    Ptr<MgPropertyCollection> props = asuf.Execute(resource, cmds, trans);
+
+    if (cmds->GetCount() == 1)
+    {
+        INT32 i = 0;
+        Ptr<MgProperty> prop = props->GetItem(i);
+        if (prop->GetPropertyType() == MgPropertyType::String) //FDO error in non-transactional mode
+        {
+            MgStringProperty* sp = static_cast<MgStringProperty*>(prop.p);
+            MgStringCollection args;
+            args.Add(sp->GetValue());
+            throw new MgFdoException(L"MgServerFeatureService.InsertFeatures", __LINE__, __WFILE__, &args, L"MgFormatInnerExceptionMessage", NULL);
+        }
+        else if (prop->GetPropertyType() == MgPropertyType::Feature) //Insert result
+        {
+            MgFeatureProperty* fp = static_cast<MgFeatureProperty*>(prop.p);
+            ret = fp->GetValue();
+        }
+    }
+
+    MG_FEATURE_SERVICE_CATCH_AND_THROW_WITH_FEATURE_SOURCE(L"MgServerFeatureService.InsertFeatures", resource)
+    return ret.Detach();
+}
+
+INT32 MgServerFeatureService::UpdateMatchingFeatures(MgResourceIdentifier* resource,
+                                                     CREFSTRING className,
+                                                     MgPropertyCollection* properties,
+                                                     CREFSTRING filter)
+{
+    MG_LOG_TRACE_ENTRY(L"MgServerFeatureService::UpdateMatchingFeatures()");
+
+    INT32 ret = -1;
+    MG_FEATURE_SERVICE_TRY()
+    
+    Ptr<MgUpdateFeatures> update = new MgUpdateFeatures(className, properties, filter);
+    Ptr<MgFeatureCommandCollection> cmds = new MgFeatureCommandCollection();
+    cmds->Add(update);
+    MgServerUpdateFeatures asuf;
+    Ptr<MgPropertyCollection> props = asuf.Execute(resource, cmds, false);
+
+    if (cmds->GetCount() == 1)
+    {
+        INT32 i = 0;
+        Ptr<MgProperty> prop = props->GetItem(i);
+        if (prop->GetPropertyType() == MgPropertyType::String) //FDO error in non-transactional mode
+        {
+            MgStringProperty* sp = static_cast<MgStringProperty*>(prop.p);
+            MgStringCollection args;
+            args.Add(sp->GetValue());
+            throw new MgFdoException(L"MgServerFeatureService.UpdateMatchingFeatures", __LINE__, __WFILE__, &args, L"MgFormatInnerExceptionMessage", NULL);
+        }
+        else if (prop->GetPropertyType() == MgPropertyType::Int32) //Update result
+        {
+            MgInt32Property* ip = static_cast<MgInt32Property*>(prop.p);
+            ret = ip->GetValue();
+        }
+    }
+
+    MG_FEATURE_SERVICE_CATCH_AND_THROW_WITH_FEATURE_SOURCE(L"MgServerFeatureService.UpdateMatchingFeatures", resource)
+    return ret;
+}
+
+INT32 MgServerFeatureService::UpdateMatchingFeatures(MgResourceIdentifier* resource,
+                                                     CREFSTRING className,
+                                                     MgPropertyCollection* properties,
+                                                     CREFSTRING filter,
+                                                     MgTransaction* trans)
+{
+    MG_LOG_TRACE_ENTRY(L"MgServerFeatureService::UpdateMatchingFeatures()");
+
+    INT32 ret = -1;
+    MG_FEATURE_SERVICE_TRY()
+    
+    Ptr<MgUpdateFeatures> update = new MgUpdateFeatures(className, properties, filter);
+    Ptr<MgFeatureCommandCollection> cmds = new MgFeatureCommandCollection();
+    cmds->Add(update);
+    MgServerUpdateFeatures asuf;
+    Ptr<MgPropertyCollection> props = asuf.Execute(resource, cmds, trans);
+
+    if (cmds->GetCount() == 1)
+    {
+        INT32 i = 0;
+        Ptr<MgProperty> prop = props->GetItem(i);
+        if (prop->GetPropertyType() == MgPropertyType::String) //FDO error in non-transactional mode
+        {
+            MgStringProperty* sp = static_cast<MgStringProperty*>(prop.p);
+            MgStringCollection args;
+            args.Add(sp->GetValue());
+            throw new MgFdoException(L"MgServerFeatureService.UpdateMatchingFeatures", __LINE__, __WFILE__, &args, L"MgFormatInnerExceptionMessage", NULL);
+        }
+        else if (prop->GetPropertyType() == MgPropertyType::Int32) //Update result
+        {
+            MgInt32Property* ip = static_cast<MgInt32Property*>(prop.p);
+            ret = ip->GetValue();
+        }
+    }
+
+    MG_FEATURE_SERVICE_CATCH_AND_THROW_WITH_FEATURE_SOURCE(L"MgServerFeatureService.UpdateMatchingFeatures", resource)
+    return ret;
+}
+
+INT32 MgServerFeatureService::DeleteFeatures(MgResourceIdentifier* resource,
+                                             CREFSTRING className,
+                                             CREFSTRING filter)
+{
+    MG_LOG_TRACE_ENTRY(L"MgServerFeatureService::DeleteFeatures()");
+
+    INT32 ret = -1;
+    MG_FEATURE_SERVICE_TRY()
+    
+    Ptr<MgDeleteFeatures> deleteCmd = new MgDeleteFeatures(className, filter);
+    Ptr<MgFeatureCommandCollection> cmds = new MgFeatureCommandCollection();
+    cmds->Add(deleteCmd);
+    MgServerUpdateFeatures asuf;
+    Ptr<MgPropertyCollection> props = asuf.Execute(resource, cmds, false);
+
+    if (cmds->GetCount() == 1)
+    {
+        INT32 i = 0;
+        Ptr<MgProperty> prop = props->GetItem(i);
+        if (prop->GetPropertyType() == MgPropertyType::String) //FDO error in non-transactional mode
+        {
+            MgStringProperty* sp = static_cast<MgStringProperty*>(prop.p);
+            MgStringCollection args;
+            args.Add(sp->GetValue());
+            throw new MgFdoException(L"MgServerFeatureService.DeleteFeatures", __LINE__, __WFILE__, &args, L"MgFormatInnerExceptionMessage", NULL);
+        }
+        else if (prop->GetPropertyType() == MgPropertyType::Int32) //Delete result
+        {
+            MgInt32Property* ip = static_cast<MgInt32Property*>(prop.p);
+            ret = ip->GetValue();
+        }
+    }
+
+    MG_FEATURE_SERVICE_CATCH_AND_THROW_WITH_FEATURE_SOURCE(L"MgServerFeatureService.UpdateMatchingFeatures", resource)
+    return ret;
+}
+
+INT32 MgServerFeatureService::DeleteFeatures(MgResourceIdentifier* resource,
+                                             CREFSTRING className,
+                                             CREFSTRING filter,
+                                             MgTransaction* trans)
+{
+    MG_LOG_TRACE_ENTRY(L"MgServerFeatureService::DeleteFeatures()");
+
+    INT32 ret = -1;
+    MG_FEATURE_SERVICE_TRY()
+    
+    Ptr<MgDeleteFeatures> deleteCmd = new MgDeleteFeatures(className, filter);
+    Ptr<MgFeatureCommandCollection> cmds = new MgFeatureCommandCollection();
+    cmds->Add(deleteCmd);
+    MgServerUpdateFeatures asuf;
+    Ptr<MgPropertyCollection> props = asuf.Execute(resource, cmds, trans);
+
+    if (cmds->GetCount() == 1)
+    {
+        INT32 i = 0;
+        Ptr<MgProperty> prop = props->GetItem(i);
+        if (prop->GetPropertyType() == MgPropertyType::String) //FDO error in non-transactional mode
+        {
+            MgStringProperty* sp = static_cast<MgStringProperty*>(prop.p);
+            MgStringCollection args;
+            args.Add(sp->GetValue());
+            throw new MgFdoException(L"MgServerFeatureService.DeleteFeatures", __LINE__, __WFILE__, &args, L"MgFormatInnerExceptionMessage", NULL);
+        }
+        else if (prop->GetPropertyType() == MgPropertyType::Int32) //Delete result
+        {
+            MgInt32Property* ip = static_cast<MgInt32Property*>(prop.p);
+            ret = ip->GetValue();
+        }
+    }
+
+    MG_FEATURE_SERVICE_CATCH_AND_THROW_WITH_FEATURE_SOURCE(L"MgServerFeatureService.UpdateMatchingFeatures", resource)
+    return ret;
+}
+
 ////////////////////////////////////////////////////////////////////////////////////////
 /// <summary>
 /// Gets the locked features

Modified: trunk/MgDev/Server/src/Services/Feature/ServerFeatureService.h
===================================================================
--- trunk/MgDev/Server/src/Services/Feature/ServerFeatureService.h	2014-10-07 09:31:27 UTC (rev 8393)
+++ trunk/MgDev/Server/src/Services/Feature/ServerFeatureService.h	2014-10-08 01:36:51 UTC (rev 8394)
@@ -992,6 +992,44 @@
     ///
     void CreateFeatureSource(MgResourceIdentifier* resource, MgFeatureSourceParams* sourceParams);
 
+    virtual MgFeatureReader* InsertFeatures(MgResourceIdentifier* resource,
+                                            CREFSTRING className,
+                                            MgPropertyCollection* propertyValues);
+
+    virtual MgFeatureReader* InsertFeatures(MgResourceIdentifier* resource,
+                                            CREFSTRING className,
+                                            MgPropertyCollection* propertyValues,
+                                            MgTransaction* trans);
+
+    virtual MgFeatureReader* InsertFeatures(MgResourceIdentifier* resource,
+                                            CREFSTRING className,
+                                            MgBatchPropertyCollection* batchPropertyValues);
+
+    virtual MgFeatureReader* InsertFeatures(MgResourceIdentifier* resource,
+                                            CREFSTRING className,
+                                            MgBatchPropertyCollection* batchPropertyValues,
+                                            MgTransaction* trans);
+
+    virtual INT32 UpdateMatchingFeatures(MgResourceIdentifier* resource,
+                                         CREFSTRING className,
+                                         MgPropertyCollection* properties,
+                                         CREFSTRING filter);
+
+    virtual INT32 UpdateMatchingFeatures(MgResourceIdentifier* resource,
+                                         CREFSTRING className,
+                                         MgPropertyCollection* properties,
+                                         CREFSTRING filter,
+                                         MgTransaction* trans);
+
+    virtual INT32 DeleteFeatures(MgResourceIdentifier* resource,
+                                 CREFSTRING className,
+                                 CREFSTRING filter);
+
+    virtual INT32 DeleteFeatures(MgResourceIdentifier* resource,
+                                 CREFSTRING className,
+                                 CREFSTRING filter,
+                                 MgTransaction* trans);
+
     // Feature
     MgBatchPropertyCollection* GetFeatures(CREFSTRING featureReader);
     bool CloseFeatureReader(CREFSTRING featureReader);

Modified: trunk/MgDev/Server/src/Services/Feature/ServerFeatureService.vcxproj
===================================================================
--- trunk/MgDev/Server/src/Services/Feature/ServerFeatureService.vcxproj	2014-10-07 09:31:27 UTC (rev 8393)
+++ trunk/MgDev/Server/src/Services/Feature/ServerFeatureService.vcxproj	2014-10-08 01:36:51 UTC (rev 8394)
@@ -277,6 +277,12 @@
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
     </ClCompile>
+    <ClCompile Include="OpDeleteFeatures.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="OpDescribeSchema.cpp">
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
@@ -409,6 +415,18 @@
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">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>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
+    </ClCompile>
+    <ClCompile Include="OpInsertFeaturesBatched.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="OpReleaseSavePoint.cpp">
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
@@ -483,6 +501,12 @@
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
     </ClCompile>
+    <ClCompile Include="OpUpdateMatchingFeatures.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="OpXmlToSchema.cpp">
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
@@ -786,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" />
@@ -799,6 +829,7 @@
     <ClInclude Include="OpCloseSqlReader.h" />
     <ClInclude Include="OpCommitTransaction.h" />
     <ClInclude Include="OpCreateFeatureSource.h" />
+    <ClInclude Include="OpDeleteFeatures.h" />
     <ClInclude Include="OpDescribeSchema.h" />
     <ClInclude Include="OpDescribeSchemaAsXml.h" />
     <ClInclude Include="OpDescribeWfsFeatureType.h" />
@@ -821,6 +852,8 @@
     <ClInclude Include="OpGetSpatialContexts.h" />
     <ClInclude Include="OpGetSqlRows.h" />
     <ClInclude Include="OpGetWfsFeature.h" />
+    <ClInclude Include="OpInsertFeatures.h" />
+    <ClInclude Include="OpInsertFeaturesBatched.h" />
     <ClInclude Include="OpReleaseSavePoint.h" />
     <ClInclude Include="OpRollbackSavePoint.h" />
     <ClInclude Include="OpRollbackTransaction.h" />
@@ -832,6 +865,7 @@
     <ClInclude Include="OpTestFeatureSourceConnection.h" />
     <ClInclude Include="OpUpdateFeatures.h" />
     <ClInclude Include="OpUpdateFeaturesWithTransaction.h" />
+    <ClInclude Include="OpUpdateMatchingFeatures.h" />
     <ClInclude Include="OpXmlToSchema.h" />
     <ClInclude Include="BooleanDataReaderCreator.h" />
     <ClInclude Include="ByteDataReaderCreator.h" />
@@ -906,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: trunk/MgDev/Server/src/Services/Feature/ServerFeatureService.vcxproj.filters
===================================================================
--- trunk/MgDev/Server/src/Services/Feature/ServerFeatureService.vcxproj.filters	2014-10-07 09:31:27 UTC (rev 8393)
+++ trunk/MgDev/Server/src/Services/Feature/ServerFeatureService.vcxproj.filters	2014-10-08 01:36:51 UTC (rev 8394)
@@ -188,6 +188,19 @@
     <ClCompile Include="ServerUpdateFeatures.cpp" />
     <ClCompile Include="TransformCache.cpp" />
     <ClCompile Include="FdoForcedOneToOneFeatureReader.cpp" />
+    <ClCompile Include="OpInsertFeatures.cpp">
+      <Filter>Ops</Filter>
+    </ClCompile>
+    <ClCompile Include="OpUpdateMatchingFeatures.cpp">
+      <Filter>Ops</Filter>
+    </ClCompile>
+    <ClCompile Include="OpDeleteFeatures.cpp">
+      <Filter>Ops</Filter>
+    </ClCompile>
+    <ClCompile Include="OpInsertFeaturesBatched.cpp">
+      <Filter>Ops</Filter>
+    </ClCompile>
+    <ClCompile Include="TransformedGeometryFeatureReader.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="FeatureOperation.h">
@@ -385,6 +398,19 @@
     <ClInclude Include="TransformCache.h" />
     <ClInclude Include="UniqueFunction.h" />
     <ClInclude Include="FdoForcedOneToOneFeatureReader.h" />
+    <ClInclude Include="OpInsertFeatures.h">
+      <Filter>Ops</Filter>
+    </ClInclude>
+    <ClInclude Include="OpUpdateMatchingFeatures.h">
+      <Filter>Ops</Filter>
+    </ClInclude>
+    <ClInclude Include="OpDeleteFeatures.h">
+      <Filter>Ops</Filter>
+    </ClInclude>
+    <ClInclude Include="OpInsertFeaturesBatched.h">
+      <Filter>Ops</Filter>
+    </ClInclude>
+    <ClInclude Include="TransformedGeometryFeatureReader.h" />
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="ServerFeatureService.rc" />

Modified: trunk/MgDev/Server/src/Services/Feature/ServerFeatureServiceBuild.cpp
===================================================================
--- trunk/MgDev/Server/src/Services/Feature/ServerFeatureServiceBuild.cpp	2014-10-07 09:31:27 UTC (rev 8393)
+++ trunk/MgDev/Server/src/Services/Feature/ServerFeatureServiceBuild.cpp	2014-10-08 01:36:51 UTC (rev 8394)
@@ -107,3 +107,8 @@
 #include "OpCommitTransaction.cpp"
 #include "OpRollbackTransaction.cpp"
 #include "OpUpdateFeaturesWithTransaction.cpp"
+#include "OpInsertFeatures.cpp"
+#include "OpInsertFeaturesBatched.cpp"
+#include "OpUpdateMatchingFeatures.cpp"
+#include "OpDeleteFeatures.cpp"
+#include "TransformedGeometryFeatureReader.cpp"

Modified: trunk/MgDev/Server/src/Services/Feature/ServerFeatureUtil.cpp
===================================================================
--- trunk/MgDev/Server/src/Services/Feature/ServerFeatureUtil.cpp	2014-10-07 09:31:27 UTC (rev 8393)
+++ trunk/MgDev/Server/src/Services/Feature/ServerFeatureUtil.cpp	2014-10-08 01:36:51 UTC (rev 8394)
@@ -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


Property changes on: trunk/MgDev/Server/src/Services/Feature/ServerFeatureUtil.cpp
___________________________________________________________________
Modified: svn:mergeinfo
   - /branches/2.4/MgDev/Server/src/Services/Feature/ServerFeatureUtil.cpp:6738-6741,6749-6756,6777-6783,6785-6787,6789,6791-6794,6796-6801,6954-6962,6986-7006
/sandbox/adsk/2.4j/Server/src/Services/Feature/ServerFeatureUtil.cpp:6327-6481
/sandbox/jng/createruntimemap/Server/src/Services/Feature/ServerFeatureUtil.cpp:7486-7555
/sandbox/rfc94/Server/src/Services/Feature/ServerFeatureUtil.cpp:5099-5163
/trunk/MgDev/Server/src/Services/Feature/ServerFeatureUtil.cpp:6250-6326
   + /branches/2.4/MgDev/Server/src/Services/Feature/ServerFeatureUtil.cpp:6738-6741,6749-6756,6777-6783,6785-6787,6789,6791-6794,6796-6801,6954-6962,6986-7006
/sandbox/adsk/2.4j/Server/src/Services/Feature/ServerFeatureUtil.cpp:6327-6481
/sandbox/jng/convenience_apis/Server/src/Services/Feature/ServerFeatureUtil.cpp:8264-8268
/sandbox/jng/createruntimemap/Server/src/Services/Feature/ServerFeatureUtil.cpp:7486-7555
/sandbox/rfc94/Server/src/Services/Feature/ServerFeatureUtil.cpp:5099-5163
/trunk/MgDev/Server/src/Services/Feature/ServerFeatureUtil.cpp:6250-6326

Modified: trunk/MgDev/Server/src/Services/Feature/ServerFeatureUtil.h
===================================================================
--- trunk/MgDev/Server/src/Services/Feature/ServerFeatureUtil.h	2014-10-07 09:31:27 UTC (rev 8393)
+++ trunk/MgDev/Server/src/Services/Feature/ServerFeatureUtil.h	2014-10-08 01:36:51 UTC (rev 8394)
@@ -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();
 

Copied: trunk/MgDev/Server/src/Services/Feature/TransformedGeometryFeatureReader.cpp (from rev 8268, sandbox/jng/convenience_apis/Server/src/Services/Feature/TransformedGeometryFeatureReader.cpp)
===================================================================
--- trunk/MgDev/Server/src/Services/Feature/TransformedGeometryFeatureReader.cpp	                        (rev 0)
+++ trunk/MgDev/Server/src/Services/Feature/TransformedGeometryFeatureReader.cpp	2014-10-08 01:36:51 UTC (rev 8394)
@@ -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

Copied: trunk/MgDev/Server/src/Services/Feature/TransformedGeometryFeatureReader.h (from rev 8268, sandbox/jng/convenience_apis/Server/src/Services/Feature/TransformedGeometryFeatureReader.h)
===================================================================
--- trunk/MgDev/Server/src/Services/Feature/TransformedGeometryFeatureReader.h	                        (rev 0)
+++ trunk/MgDev/Server/src/Services/Feature/TransformedGeometryFeatureReader.h	2014-10-08 01:36:51 UTC (rev 8394)
@@ -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: trunk/MgDev/Server/src/UnitTesting/TestFeatureService.cpp
===================================================================
--- trunk/MgDev/Server/src/UnitTesting/TestFeatureService.cpp	2014-10-07 09:31:27 UTC (rev 8393)
+++ trunk/MgDev/Server/src/UnitTesting/TestFeatureService.cpp	2014-10-08 01:36:51 UTC (rev 8394)
@@ -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:
 ///
@@ -2971,4 +3099,557 @@
     {
         throw;
     }
+}
+
+void TestFeatureService::TestCase_InsertFeatures()
+{
+    try
+    {
+        MgServiceManager* serviceManager = MgServiceManager::GetInstance();
+        if(serviceManager == 0)
+        {
+            throw new MgNullReferenceException(L"TestFeatureService.TestCase_InsertFeatures", __LINE__, __WFILE__, NULL, L"", NULL);
+        }
+
+        Ptr<MgFeatureService> featSvc = dynamic_cast<MgFeatureService*>(serviceManager->RequestService(MgServiceType::FeatureService));
+        if (featSvc == 0)
+        {
+            throw new MgServiceNotAvailableException(L"TestFeatureService.TestCase_InsertFeatures",
+                __LINE__, __WFILE__, NULL, L"", NULL);
+        }
+
+        Ptr<MgResourceIdentifier> fsId = new MgResourceIdentifier(L"Library://UnitTests/Data/TestCase_InsertFeatures.FeatureSource");
+        STRING className = CreateTestDataStore(featSvc, L"OSGeo.SDF", fsId);
+
+        Ptr<MgPropertyCollection> props = new MgPropertyCollection();
+        Ptr<MgStringProperty> nameProp = new MgStringProperty(L"Name", L"");
+        Ptr<MgGeometryProperty> geomProp = new MgGeometryProperty(L"Geometry", NULL);
+        props->Add(nameProp);
+        props->Add(geomProp);
+
+        MgAgfReaderWriter agfRw;
+        MgWktReaderWriter wktRw;
+
+        nameProp->SetValue(L"Test");
+        Ptr<MgGeometry> geom = wktRw.Read(L"POINT (1 1)");
+        Ptr<MgByteReader> agf = agfRw.Write(geom);
+        geomProp->SetValue(agf);
+
+        Ptr<MgReader> fr = featSvc->InsertFeatures(fsId, className, props);
+        INT32 count = 0;
+        while (fr->ReadNext())
+        {
+            count++;
+        }
+        fr->Close();
+        CPPUNIT_ASSERT(1 == count);
+
+        Ptr<MgFeatureQueryOptions> query = new MgFeatureQueryOptions();
+        fr = featSvc->SelectFeatures(fsId, className, query);
+        count = 0;
+        while(fr->ReadNext())
+        {
+            CPPUNIT_ASSERT(fr->GetString(L"Name") == L"Test");
+            agf = fr->GetGeometry(L"Geometry");
+            geom = agfRw.Read(agf);
+            CPPUNIT_ASSERT(wktRw.Write(geom) == L"POINT (1 1)");
+            count++;
+        }
+        fr->Close();
+        CPPUNIT_ASSERT(1 == count);
+    }
+    catch(MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch(FdoException* e)
+    {
+        STRING message = L"FdoException occurred: ";
+        message += e->GetExceptionMessage();
+        FDO_SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch(...)
+    {
+        throw;
+    }
+}
+
+void TestFeatureService::TestCase_InsertFeaturesBatch()
+{
+    try
+    {
+        MgServiceManager* serviceManager = MgServiceManager::GetInstance();
+        if(serviceManager == 0)
+        {
+            throw new MgNullReferenceException(L"TestFeatureService.TestCase_InsertFeatures", __LINE__, __WFILE__, NULL, L"", NULL);
+        }
+
+        Ptr<MgFeatureService> featSvc = dynamic_cast<MgFeatureService*>(serviceManager->RequestService(MgServiceType::FeatureService));
+        if (featSvc == 0)
+        {
+            throw new MgServiceNotAvailableException(L"TestFeatureService.TestCase_InsertFeatures",
+                __LINE__, __WFILE__, NULL, L"", NULL);
+        }
+
+        Ptr<MgResourceIdentifier> fsId = new MgResourceIdentifier(L"Library://UnitTests/Data/TestCase_InsertFeatures.FeatureSource");
+        STRING className = CreateTestDataStore(featSvc, L"OSGeo.SDF", fsId);
+
+        Ptr<MgBatchPropertyCollection> batchProps = new MgBatchPropertyCollection();
+
+        for (INT32 i = 0; i < 5; i++)
+        {
+            Ptr<MgPropertyCollection> props = new MgPropertyCollection();
+            Ptr<MgStringProperty> nameProp = new MgStringProperty(L"Name", L"");
+            Ptr<MgGeometryProperty> geomProp = new MgGeometryProperty(L"Geometry", NULL);
+            props->Add(nameProp);
+            props->Add(geomProp);
+
+            MgAgfReaderWriter agfRw;
+            MgWktReaderWriter wktRw;
+
+            STRING str = L"Test";
+            STRING sNum;
+            MgUtil::Int32ToString((i+1), sNum);
+            str += sNum;
+
+            nameProp->SetValue(str);
+            Ptr<MgGeometry> geom = wktRw.Read(L"POINT (1 1)");
+            Ptr<MgByteReader> agf = agfRw.Write(geom);
+            geomProp->SetValue(agf);
+
+            batchProps->Add(props);
+        }
+        Ptr<MgReader> fr = featSvc->InsertFeatures(fsId, className, batchProps);
+        INT32 count = 0;
+        while (fr->ReadNext())
+        {
+            count++;
+        }
+        fr->Close();
+        CPPUNIT_ASSERT(5 == count);
+
+        Ptr<MgFeatureQueryOptions> query = new MgFeatureQueryOptions();
+        fr = featSvc->SelectFeatures(fsId, className, query);
+        count = 0;
+        while(fr->ReadNext())
+        {
+            count++;
+        }
+        fr->Close();
+        CPPUNIT_ASSERT(5 == count);
+    }
+    catch(MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch(FdoException* e)
+    {
+        STRING message = L"FdoException occurred: ";
+        message += e->GetExceptionMessage();
+        FDO_SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch(...)
+    {
+        throw;
+    }
+}
+
+void TestFeatureService::TestCase_UpdateMatchingFeatures()
+{
+    try
+    {
+        MgServiceManager* serviceManager = MgServiceManager::GetInstance();
+        if(serviceManager == 0)
+        {
+            throw new MgNullReferenceException(L"TestFeatureService.TestCase_UpdateMatchingFeatures", __LINE__, __WFILE__, NULL, L"", NULL);
+        }
+
+        Ptr<MgFeatureService> featSvc = dynamic_cast<MgFeatureService*>(serviceManager->RequestService(MgServiceType::FeatureService));
+        if (featSvc == 0)
+        {
+            throw new MgServiceNotAvailableException(L"TestFeatureService.TestCase_UpdateMatchingFeatures",
+                __LINE__, __WFILE__, NULL, L"", NULL);
+        }
+
+        Ptr<MgResourceIdentifier> fsId = new MgResourceIdentifier(L"Library://UnitTests/Data/TestCase_InsertFeatures.FeatureSource");
+        STRING className = CreateTestDataStore(featSvc, L"OSGeo.SDF", fsId);
+
+        Ptr<MgPropertyCollection> props = new MgPropertyCollection();
+        Ptr<MgStringProperty> nameProp = new MgStringProperty(L"Name", L"");
+        Ptr<MgGeometryProperty> geomProp = new MgGeometryProperty(L"Geometry", NULL);
+        props->Add(nameProp);
+        props->Add(geomProp);
+
+        MgAgfReaderWriter agfRw;
+        MgWktReaderWriter wktRw;
+
+        for (INT32 i = 0; i < 5; i++)
+        {
+            STRING str = L"Test";
+            STRING sNum;
+            MgUtil::Int32ToString((i+1), sNum);
+            str += sNum;
+            nameProp->SetValue(str);
+            Ptr<MgGeometry> geom = wktRw.Read(L"POINT (1 1)");
+            Ptr<MgByteReader> agf = agfRw.Write(geom);
+            geomProp->SetValue(agf);
+
+            Ptr<MgReader> fr = featSvc->InsertFeatures(fsId, className, props);
+            INT32 count = 0;
+            while (fr->ReadNext())
+            {
+                count++;
+            }
+            fr->Close();
+            CPPUNIT_ASSERT(1 == count);
+        }
+
+        Ptr<MgFeatureQueryOptions> query = new MgFeatureQueryOptions();
+        Ptr<MgReader> fr = featSvc->SelectFeatures(fsId, className, query);
+        INT32 count = 0;
+        while(fr->ReadNext())
+        {
+            count++;
+        }
+        fr->Close();
+        CPPUNIT_ASSERT(5 == count);
+
+        Ptr<MgPropertyCollection> updateProps = new MgPropertyCollection();
+        Ptr<MgStringProperty> newNameProp = new MgStringProperty(L"Name", L"Test3Updated");
+        updateProps->Add(newNameProp);
+        Ptr<MgGeometry> newGeom = wktRw.Read(L"POINT (2 2)");
+        Ptr<MgByteReader> newAgf = agfRw.Write(newGeom);
+        Ptr<MgGeometryProperty> newGeomProp = new MgGeometryProperty(L"Geometry", newAgf);
+        updateProps->Add(newGeomProp);
+
+        INT32 updated = featSvc->UpdateMatchingFeatures(fsId, className, updateProps, L"Name = 'Test3'");
+        CPPUNIT_ASSERT(1 == updated);
+
+        query->SetFilter(L"Name = 'Test3'");
+        fr = featSvc->SelectFeatures(fsId, className, query);
+        count = 0;
+        while(fr->ReadNext())
+        {
+            count++;
+        }
+        fr->Close();
+        CPPUNIT_ASSERT(0 == count);
+
+        query->SetFilter(L"Name = 'Test3Updated'");
+        fr = featSvc->SelectFeatures(fsId, className, query);
+        count = 0;
+        while(fr->ReadNext())
+        {
+            count++;
+        }
+        fr->Close();
+        CPPUNIT_ASSERT(1 == count);
+    }
+    catch(MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch(FdoException* e)
+    {
+        STRING message = L"FdoException occurred: ";
+        message += e->GetExceptionMessage();
+        FDO_SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch(...)
+    {
+        throw;
+    }
+}
+
+void TestFeatureService::TestCase_DeleteFeatures()
+{
+    try
+    {
+        MgServiceManager* serviceManager = MgServiceManager::GetInstance();
+        if(serviceManager == 0)
+        {
+            throw new MgNullReferenceException(L"TestFeatureService.TestCase_DeleteFeatures", __LINE__, __WFILE__, NULL, L"", NULL);
+        }
+
+        Ptr<MgFeatureService> featSvc = dynamic_cast<MgFeatureService*>(serviceManager->RequestService(MgServiceType::FeatureService));
+        if (featSvc == 0)
+        {
+            throw new MgServiceNotAvailableException(L"TestFeatureService.TestCase_DeleteFeatures",
+                __LINE__, __WFILE__, NULL, L"", NULL);
+        }
+
+        Ptr<MgResourceIdentifier> fsId = new MgResourceIdentifier(L"Library://UnitTests/Data/TestCase_InsertFeatures.FeatureSource");
+        STRING className = CreateTestDataStore(featSvc, L"OSGeo.SDF", fsId);
+
+        Ptr<MgPropertyCollection> props = new MgPropertyCollection();
+        Ptr<MgStringProperty> nameProp = new MgStringProperty(L"Name", L"");
+        Ptr<MgGeometryProperty> geomProp = new MgGeometryProperty(L"Geometry", NULL);
+        props->Add(nameProp);
+        props->Add(geomProp);
+
+        MgAgfReaderWriter agfRw;
+        MgWktReaderWriter wktRw;
+
+        for (INT32 i = 0; i < 5; i++)
+        {
+            STRING str = L"Test";
+            STRING sNum;
+            MgUtil::Int32ToString((i+1), sNum);
+            str += sNum;
+            nameProp->SetValue(str);
+            Ptr<MgGeometry> geom = wktRw.Read(L"POINT (1 1)");
+            Ptr<MgByteReader> agf = agfRw.Write(geom);
+            geomProp->SetValue(agf);
+
+            Ptr<MgReader> fr = featSvc->InsertFeatures(fsId, className, props);
+            INT32 count = 0;
+            while (fr->ReadNext())
+            {
+                count++;
+            }
+            fr->Close();
+            CPPUNIT_ASSERT(1 == count);
+        }
+
+        Ptr<MgFeatureQueryOptions> query = new MgFeatureQueryOptions();
+        Ptr<MgReader> fr = featSvc->SelectFeatures(fsId, className, query);
+        INT32 count = 0;
+        while(fr->ReadNext())
+        {
+            count++;
+        }
+        fr->Close();
+        CPPUNIT_ASSERT(5 == count);
+
+        INT32 deleted = featSvc->DeleteFeatures(fsId, className, L"Name = 'Test3'");
+        CPPUNIT_ASSERT(1 == deleted);
+
+        query->SetFilter(L"Name = 'Test3'");
+        fr = featSvc->SelectFeatures(fsId, className, query);
+        count = 0;
+        while(fr->ReadNext())
+        {
+            count++;
+        }
+        fr->Close();
+        CPPUNIT_ASSERT(0 == count);
+
+        query = new MgFeatureQueryOptions();
+        fr = featSvc->SelectFeatures(fsId, className, query);
+        count = 0;
+        while(fr->ReadNext())
+        {
+            count++;
+        }
+        fr->Close();
+        CPPUNIT_ASSERT(4 == count);
+    }
+    catch(MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch(FdoException* e)
+    {
+        STRING message = L"FdoException occurred: ";
+        message += e->GetExceptionMessage();
+        FDO_SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch(...)
+    {
+        throw;
+    }
+}
+
+void TestFeatureService::TestCase_TransactedCrud()
+{
+    try
+    {
+        MgServiceManager* serviceManager = MgServiceManager::GetInstance();
+        if(serviceManager == 0)
+        {
+            throw new MgNullReferenceException(L"TestFeatureService.TestCase_TransactedCrud", __LINE__, __WFILE__, NULL, L"", NULL);
+        }
+
+        Ptr<MgFeatureService> featSvc = dynamic_cast<MgFeatureService*>(serviceManager->RequestService(MgServiceType::FeatureService));
+        if (featSvc == 0)
+        {
+            throw new MgServiceNotAvailableException(L"TestFeatureService.TestCase_TransactedCrud",
+                __LINE__, __WFILE__, NULL, L"", NULL);
+        }
+
+        Ptr<MgResourceIdentifier> fsId = new MgResourceIdentifier(L"Library://UnitTests/Data/TestCase_InsertFeatures.FeatureSource");
+        STRING className = CreateTestDataStore(featSvc, L"OSGeo.SQLite", fsId);
+
+        Ptr<MgPropertyCollection> props = new MgPropertyCollection();
+        Ptr<MgStringProperty> nameProp = new MgStringProperty(L"Name", L"");
+        Ptr<MgGeometryProperty> geomProp = new MgGeometryProperty(L"Geometry", NULL);
+        props->Add(nameProp);
+        props->Add(geomProp);
+
+        MgAgfReaderWriter agfRw;
+        MgWktReaderWriter wktRw;
+
+        for (INT32 i = 0; i < 5; i++)
+        {
+            STRING str = L"Test";
+            STRING sNum;
+            MgUtil::Int32ToString((i+1), sNum);
+            str += sNum;
+            nameProp->SetValue(str);
+            Ptr<MgGeometry> geom = wktRw.Read(L"POINT (1 1)");
+            Ptr<MgByteReader> agf = agfRw.Write(geom);
+            geomProp->SetValue(agf);
+
+            Ptr<MgReader> fr = featSvc->InsertFeatures(fsId, className, props);
+            INT32 count = 0;
+            while (fr->ReadNext())
+            {
+                count++;
+            }
+            fr->Close();
+            CPPUNIT_ASSERT(1 == count);
+        }
+
+        Ptr<MgFeatureQueryOptions> query = new MgFeatureQueryOptions();
+        Ptr<MgReader> fr = featSvc->SelectFeatures(fsId, className, query);
+        INT32 count = 0;
+        while(fr->ReadNext())
+        {
+            count++;
+        }
+        fr->Close();
+        CPPUNIT_ASSERT(5 == count);
+
+        //Do a transacted update
+        Ptr<MgTransaction> trans = featSvc->BeginTransaction(fsId);
+        
+        Ptr<MgPropertyCollection> updateProps = new MgPropertyCollection();
+        Ptr<MgStringProperty> newNameProp = new MgStringProperty(L"Name", L"Test3Updated");
+        updateProps->Add(newNameProp);
+        Ptr<MgGeometry> newGeom = wktRw.Read(L"POINT (2 2)");
+        Ptr<MgByteReader> newAgf = agfRw.Write(newGeom);
+        Ptr<MgGeometryProperty> newGeomProp = new MgGeometryProperty(L"Geometry", newAgf);
+        updateProps->Add(newGeomProp);
+
+        INT32 updated = featSvc->UpdateMatchingFeatures(fsId, className, updateProps, L"Name = 'Test3'", trans);
+        CPPUNIT_ASSERT(1 == updated);
+
+        //This hasn't been commited yet. So roll it back and verify our update never made it
+        trans->Rollback();
+        query->SetFilter(L"Name = 'Test3Updated'");
+        fr = featSvc->SelectFeatures(fsId, className, query);
+        count = 0;
+        while(fr->ReadNext())
+        {
+            count++;
+        }
+        fr->Close();
+        CPPUNIT_ASSERT(0 == count);
+
+        //Do a transacted update. This time, commit it.
+        trans = featSvc->BeginTransaction(fsId);
+        
+        updateProps = new MgPropertyCollection();
+        newNameProp = new MgStringProperty(L"Name", L"Test3Updated");
+        updateProps->Add(newNameProp);
+        newGeom = wktRw.Read(L"POINT (2 2)");
+        newAgf = agfRw.Write(newGeom);
+        newGeomProp = new MgGeometryProperty(L"Geometry", newAgf);
+        updateProps->Add(newGeomProp);
+
+        updated = featSvc->UpdateMatchingFeatures(fsId, className, updateProps, L"Name = 'Test3'", trans);
+        CPPUNIT_ASSERT(1 == updated);
+        trans->Commit();
+
+        //Verify the update came through
+        query->SetFilter(L"Name = 'Test3Updated'");
+        fr = featSvc->SelectFeatures(fsId, className, query);
+        count = 0;
+        while(fr->ReadNext())
+        {
+            count++;
+        }
+        fr->Close();
+        CPPUNIT_ASSERT(1 == count);
+    }
+    catch(MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch(FdoException* e)
+    {
+        STRING message = L"FdoException occurred: ";
+        message += e->GetExceptionMessage();
+        FDO_SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch(...)
+    {
+        throw;
+    }
+}
+
+STRING TestFeatureService::CreateTestDataStore(MgFeatureService* svcFeature, CREFSTRING provider, MgResourceIdentifier* fsId)
+{
+    Ptr<MgCoordinateSystemFactory> csFactory = new MgCoordinateSystemFactory();
+    STRING scName = L"Default";
+    STRING csWkt = csFactory->ConvertCoordinateSystemCodeToWkt(L"LL84");
+
+    Ptr<MgFeatureSchema> schema = new MgFeatureSchema(L"Default", L"Default Feature Schema");
+    Ptr<MgClassDefinition> klass = new MgClassDefinition();
+    klass->SetName(L"Test");
+
+    Ptr<MgPropertyDefinitionCollection> clsProps = klass->GetProperties();
+    Ptr<MgPropertyDefinitionCollection> clsIdProps = klass->GetIdentityProperties();
+
+    Ptr<MgDataPropertyDefinition> id = new MgDataPropertyDefinition(L"ID");
+    id->SetDataType(MgPropertyType::Int32);
+    id->SetAutoGeneration(true);
+    
+    Ptr<MgDataPropertyDefinition> name = new MgDataPropertyDefinition(L"Name");
+    name->SetDataType(MgPropertyType::String);
+    name->SetLength(255);
+    name->SetNullable(true);
+
+    Ptr<MgGeometricPropertyDefinition> geom = new MgGeometricPropertyDefinition(L"Geometry");
+    geom->SetGeometryTypes(MgFeatureGeometricType::Point);
+    geom->SetSpatialContextAssociation(scName);
+
+    clsProps->Add(id);
+    clsProps->Add(name);
+    clsProps->Add(geom);
+
+    clsIdProps->Add(id);
+
+    klass->SetDefaultGeometryPropertyName(L"Geometry");
+
+    Ptr<MgClassDefinitionCollection> classes = schema->GetClasses();
+    classes->Add(klass);
+
+    Ptr<MgFileFeatureSourceParams> fsParams = new MgFileFeatureSourceParams(provider, scName, csWkt, schema);
+    svcFeature->CreateFeatureSource(fsId, fsParams);
+
+    Ptr<MgFeatureSchemaCollection> schemas = svcFeature->DescribeSchema(fsId, L"");
+    Ptr<MgFeatureSchema> theSchema = schemas->GetItem(0);
+    Ptr<MgClassDefinitionCollection> theClasses = theSchema->GetClasses();
+    Ptr<MgClassDefinition> theClass = theClasses->GetItem(0);
+
+    STRING qClassName = theSchema->GetName();
+    qClassName += L":";
+    qClassName += theClass->GetName();
+    return qClassName;
 }
\ No newline at end of file

Modified: trunk/MgDev/Server/src/UnitTesting/TestFeatureService.h
===================================================================
--- trunk/MgDev/Server/src/UnitTesting/TestFeatureService.h	2014-10-07 09:31:27 UTC (rev 8393)
+++ trunk/MgDev/Server/src/UnitTesting/TestFeatureService.h	2014-10-08 01:36:51 UTC (rev 8394)
@@ -38,9 +38,15 @@
     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);
+    CPPUNIT_TEST(TestCase_InsertFeatures);
+    CPPUNIT_TEST(TestCase_InsertFeaturesBatch);
+    CPPUNIT_TEST(TestCase_UpdateMatchingFeatures);
+    CPPUNIT_TEST(TestCase_DeleteFeatures);
+    CPPUNIT_TEST(TestCase_TransactedCrud);
     CPPUNIT_TEST(TestCase_ExecuteSqlQuery);
     CPPUNIT_TEST(TestCase_ExecuteSqlNonQuery);
     CPPUNIT_TEST(TestCase_GetSpatialContexts);
@@ -86,9 +92,15 @@
     void TestCase_DescribeSchema();
     void TestCase_ApplySchema();
     void TestCase_SelectFeatures();
+    void TestCase_SelectFeaturesWithXform();
     void TestCase_SelectAggregate();
     void TestCase_UpdateFeaturesInsert();
     void TestCase_UpdateFeaturesPartialFailure();
+    void TestCase_InsertFeatures();
+    void TestCase_InsertFeaturesBatch();
+    void TestCase_UpdateMatchingFeatures();
+    void TestCase_DeleteFeatures();
+    void TestCase_TransactedCrud();
     void TestCase_ExecuteSqlQuery();
     void TestCase_ExecuteSqlNonQuery();
     void TestCase_GetSpatialContexts();
@@ -110,6 +122,9 @@
     void TestCase_JoinFdoFeatures();
     void TestCase_BenchmarkSqliteJoin();
     void TestCase_BenchmarkSqliteAggregateJoin();
+
+private:
+    STRING CreateTestDataStore(MgFeatureService* svcFeature, CREFSTRING provider, MgResourceIdentifier* fsId);
 };
 
 #endif // _TESTFEATURESERVICE_H

Modified: trunk/MgDev/Server/src/UnitTesting/TestMappingService.cpp
===================================================================
--- trunk/MgDev/Server/src/UnitTesting/TestMappingService.cpp	2014-10-07 09:31:27 UTC (rev 8393)
+++ trunk/MgDev/Server/src/UnitTesting/TestMappingService.cpp	2014-10-08 01:36:51 UTC (rev 8394)
@@ -138,6 +138,16 @@
         Ptr<MgByteReader> ldfrdr6 = ldfsrc6->GetReader();
         m_svcResource->SetResource(ldfres6, ldfrdr6, NULL);
 
+        Ptr<MgResourceIdentifier> ldfres7 = new MgResourceIdentifier(L"Library://UnitTests/Layers/MultiCTS.LayerDefinition");
+        Ptr<MgByteSource> ldfsrc7 = new MgByteSource(L"../UnitTestFiles/UT_MultiCTS.ldf", false);
+        Ptr<MgByteReader> ldfrdr7 = ldfsrc7->GetReader();
+        m_svcResource->SetResource(ldfres7, ldfrdr7, NULL);
+
+        Ptr<MgResourceIdentifier> ldfres8 = new MgResourceIdentifier(L"Library://UnitTests/Layers/MultiCTSWithTheme.LayerDefinition");
+        Ptr<MgByteSource> ldfsrc8 = new MgByteSource(L"../UnitTestFiles/UT_MultiCTSWithTheme.ldf", false);
+        Ptr<MgByteReader> ldfrdr8 = ldfsrc8->GetReader();
+        m_svcResource->SetResource(ldfres8, ldfrdr8, NULL);
+
         //publish the feature sources
         Ptr<MgResourceIdentifier> fsres1 = new MgResourceIdentifier(L"Library://UnitTests/Data/HydrographicPolygons.FeatureSource");
         Ptr<MgByteSource> fssrc1 = new MgByteSource(L"../UnitTestFiles/UT_HydrographicPolygons.fs", false);
@@ -242,6 +252,12 @@
         Ptr<MgResourceIdentifier> ldfres6 = new MgResourceIdentifier(L"Library://UnitTests/Layers/VotingDistricts.LayerDefinition");
         m_svcResource->DeleteResource(ldfres6);
 
+        Ptr<MgResourceIdentifier> ldfres7 = new MgResourceIdentifier(L"Library://UnitTests/Layers/MultiCTS.LayerDefinition");
+        m_svcResource->DeleteResource(ldfres7);
+
+        Ptr<MgResourceIdentifier> ldfres8 = new MgResourceIdentifier(L"Library://UnitTests/Layers/MultiCTSWithTheme.LayerDefinition");
+        m_svcResource->DeleteResource(ldfres8);
+
         //delete the feature sources
         Ptr<MgResourceIdentifier> fsres1 = new MgResourceIdentifier(L"Library://UnitTests/Data/HydrographicPolygons.FeatureSource");
         m_svcResource->DeleteResource(fsres1);
@@ -1023,6 +1039,404 @@
     }
 }
 
+void TestMappingService::TestCase_GetLegendImageConvenience()
+{
+    try
+    {
+        Ptr<MgResourceIdentifier> mapres = new MgResourceIdentifier(L"Library://UnitTests/Maps/Sheboygan.MapDefinition");
+        Ptr<MgMap> map = new MgMap(m_siteConnection);
+        map->Create(mapres, L"TestCase_GetLegendImageConvenience");
+
+        Ptr<MgResourceIdentifier> ldf = new MgResourceIdentifier(L"Library://UnitTests/Layers/Parcels.LayerDefinition");
+        Ptr<MgLayer> layer = new MgLayer(ldf, m_svcResource);
+        layer->SetName(L"TestCase_GetLegendImageConvenience");
+        Ptr<MgLayerCollection> layers = map->GetLayers();
+        layers->Insert(0, layer);
+
+        Ptr<MgIntCollection> types = layer->GetGeometryTypeStyles(10000.0);
+        CPPUNIT_ASSERT(1 == types->GetCount());
+        CPPUNIT_ASSERT(types->IndexOf(1) < 0);
+        CPPUNIT_ASSERT(types->IndexOf(2) < 0);
+        CPPUNIT_ASSERT(types->IndexOf(3) >= 0);
+        CPPUNIT_ASSERT(types->IndexOf(4) < 0);
+
+        CPPUNIT_ASSERT(8 == layer->GetThemeCategoryCount(10000.0, 3));
+        CPPUNIT_ASSERT(-1 == layer->GetThemeCategoryCount(10000.0, 1));
+        CPPUNIT_ASSERT(-1 == layer->GetThemeCategoryCount(10000.0, 2));
+        CPPUNIT_ASSERT(-1 == layer->GetThemeCategoryCount(10000.0, 4));
+
+        types = layer->GetGeometryTypeStyles(14000.0);
+        CPPUNIT_ASSERT(NULL == types.p);
+        CPPUNIT_ASSERT(-1 == layer->GetThemeCategoryCount(14000.0, 3));
+        CPPUNIT_ASSERT(-1 == layer->GetThemeCategoryCount(14000.0, 1));
+        CPPUNIT_ASSERT(-1 == layer->GetThemeCategoryCount(14000.0, 2));
+        CPPUNIT_ASSERT(-1 == layer->GetThemeCategoryCount(14000.0, 4));
+
+        Ptr<MgByteReader> rdr = layer->GenerateLegendImage(10000.0, 16, 16, MgImageFormats::Png, 3, 0);
+        Ptr<MgByteSink> sink = new MgByteSink(rdr);
+        sink->ToFile(L"../UnitTestFiles/GenerateLegendImageConvenience_Parcels_16x16_PNG.png");
+
+        rdr = layer->GenerateLegendImage(10000.0, 16, 16, MgImageFormats::Png8, 3, 0);
+        sink = new MgByteSink(rdr);
+        sink->ToFile(L"../UnitTestFiles/GenerateLegendImageConvenience_Parcels_16x16_PNG8.png");
+
+        rdr = layer->GenerateLegendImage(10000.0, 16, 16, MgImageFormats::Jpeg, 3, 0);
+        sink = new MgByteSink(rdr);
+        sink->ToFile(L"../UnitTestFiles/GenerateLegendImageConvenience_Parcels_16x16_JPG.jpg");
+
+        rdr = layer->GenerateLegendImage(10000.0, 16, 16, MgImageFormats::Gif, 3, 0);
+        sink = new MgByteSink(rdr);
+        sink->ToFile(L"../UnitTestFiles/GenerateLegendImageConvenience_Parcels_16x16_GIF.gif");
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        throw;
+    }
+}
+
+void TestMappingService::TestCase_GetLegendImageCompositeConvenience()
+{
+    try
+    {
+        Ptr<MgResourceIdentifier> mapres = new MgResourceIdentifier(L"Library://UnitTests/Maps/Sheboygan.MapDefinition");
+        Ptr<MgMap> map = new MgMap(m_siteConnection);
+        map->Create(mapres, L"TestCase_GetLegendImageCompositeConvenience");
+
+        Ptr<MgResourceIdentifier> ldf = new MgResourceIdentifier(L"Library://UnitTests/Layers/MultiCTS.LayerDefinition");
+        Ptr<MgLayer> layer = new MgLayer(ldf, m_svcResource);
+        layer->SetName(L"TestCase_GetLegendImageCompositeConvenience");
+        Ptr<MgLayerCollection> layers = map->GetLayers();
+        layers->Insert(0, layer);
+
+        Ptr<MgIntCollection> types = layer->GetGeometryTypeStyles(10000.0);
+        CPPUNIT_ASSERT(3 == types->GetCount());
+        CPPUNIT_ASSERT(types->IndexOf(1) < 0);
+        CPPUNIT_ASSERT(types->IndexOf(2) < 0);
+        CPPUNIT_ASSERT(types->IndexOf(3) < 0);
+        CPPUNIT_ASSERT(types->IndexOf(4) >= 0);
+        for (INT32 i = 0; i < types->GetCount(); i++)
+        {
+            CPPUNIT_ASSERT(4 == types->GetItem(i));
+        }
+
+        CPPUNIT_ASSERT(-1 == layer->GetThemeCategoryCount(10000.0, 1));
+        CPPUNIT_ASSERT(-1 == layer->GetThemeCategoryCount(10000.0, 2));
+        CPPUNIT_ASSERT(-1 == layer->GetThemeCategoryCount(10000.0, 3));
+        CPPUNIT_ASSERT(1 == layer->GetThemeCategoryCount(10000.0, 4));
+        CPPUNIT_ASSERT(1 == layer->GetCompositeThemeCategoryCount(10000.0, 0));
+        CPPUNIT_ASSERT(1 == layer->GetCompositeThemeCategoryCount(10000.0, 1));
+        CPPUNIT_ASSERT(1 == layer->GetCompositeThemeCategoryCount(10000.0, 2));
+        CPPUNIT_ASSERT(-1 == layer->GetCompositeThemeCategoryCount(10000.0, 3));
+
+        INT32 rulesProcessed = 0;
+        for (INT32 ctype = 0; ctype < 3; ctype++)
+        {
+            INT32 rules = layer->GetCompositeThemeCategoryCount(10000.0, ctype);
+            for (INT32 offset = rulesProcessed; offset < (rulesProcessed + rules); offset++)
+            {
+                STRING prefix = L"../UnitTestFiles/GenerateLegendImageConvenience_MultiCTS_type";
+                STRING sNum;
+                MgUtil::Int32ToString(ctype, sNum);
+                prefix += sNum;
+                prefix += L"_offset";
+                MgUtil::Int32ToString(offset, sNum);
+                prefix += sNum;
+
+                STRING fileNamePNG = prefix;
+                fileNamePNG += L"_16x16_PNG.png";
+                Ptr<MgByteReader> rdr = layer->GenerateLegendImage(10000.0, 16, 16, MgImageFormats::Png, 4, offset);
+                Ptr<MgByteSink> sink = new MgByteSink(rdr);
+                sink->ToFile(fileNamePNG);
+
+                STRING fileNamePNG8 = prefix;
+                fileNamePNG8 += L"_16x16_PNG8.png";
+                rdr = layer->GenerateLegendImage(10000.0, 16, 16, MgImageFormats::Png8, 4, offset);
+                sink = new MgByteSink(rdr);
+                sink->ToFile(fileNamePNG8);
+
+                STRING fileNameJPG = prefix;
+                fileNameJPG += L"_16x16_JPG.jpg";
+                rdr = layer->GenerateLegendImage(10000.0, 16, 16, MgImageFormats::Jpeg, 4, offset);
+                sink = new MgByteSink(rdr);
+                sink->ToFile(fileNameJPG);
+
+                STRING fileNameGIF = prefix;
+                fileNameGIF += L"_16x16_JPG.jpg";
+                rdr = layer->GenerateLegendImage(10000.0, 16, 16, MgImageFormats::Gif, 4, offset);
+                sink = new MgByteSink(rdr);
+                sink->ToFile(fileNameGIF);
+            }
+            rulesProcessed += rules;
+        }
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        throw;
+    }
+}
+
+void TestMappingService::TestCase_GetLegendImageCompositeThemedConvenience()
+{
+    try
+    {
+        Ptr<MgResourceIdentifier> mapres = new MgResourceIdentifier(L"Library://UnitTests/Maps/Sheboygan.MapDefinition");
+        Ptr<MgMap> map = new MgMap(m_siteConnection);
+        map->Create(mapres, L"TestCase_GetLegendImageCompositeThemedConvenience");
+
+        Ptr<MgResourceIdentifier> ldf = new MgResourceIdentifier(L"Library://UnitTests/Layers/MultiCTSWithTheme.LayerDefinition");
+        Ptr<MgLayer> layer = new MgLayer(ldf, m_svcResource);
+        layer->SetName(L"TestCase_GetLegendImageCompositeThemedConvenience");
+        Ptr<MgLayerCollection> layers = map->GetLayers();
+        layers->Insert(0, layer);
+
+        Ptr<MgIntCollection> types = layer->GetGeometryTypeStyles(10000.0);
+        CPPUNIT_ASSERT(3 == types->GetCount());
+        CPPUNIT_ASSERT(types->IndexOf(1) < 0);
+        CPPUNIT_ASSERT(types->IndexOf(2) < 0);
+        CPPUNIT_ASSERT(types->IndexOf(3) < 0);
+        CPPUNIT_ASSERT(types->IndexOf(4) >= 0);
+        for (INT32 i = 0; i < types->GetCount(); i++)
+        {
+            CPPUNIT_ASSERT(4 == types->GetItem(i));
+        }
+
+        CPPUNIT_ASSERT(-1 == layer->GetThemeCategoryCount(10000.0, 1));
+        CPPUNIT_ASSERT(-1 == layer->GetThemeCategoryCount(10000.0, 2));
+        CPPUNIT_ASSERT(-1 == layer->GetThemeCategoryCount(10000.0, 3));
+        CPPUNIT_ASSERT(1 == layer->GetThemeCategoryCount(10000.0, 4));
+        CPPUNIT_ASSERT(1 == layer->GetCompositeThemeCategoryCount(10000.0, 0));
+        CPPUNIT_ASSERT(3 == layer->GetCompositeThemeCategoryCount(10000.0, 1));
+        CPPUNIT_ASSERT(1 == layer->GetCompositeThemeCategoryCount(10000.0, 2));
+        CPPUNIT_ASSERT(-1 == layer->GetCompositeThemeCategoryCount(10000.0, 3));
+
+        INT32 rulesProcessed = 0;
+        for (INT32 ctype = 0; ctype < 3; ctype++)
+        {
+            INT32 rules = layer->GetCompositeThemeCategoryCount(10000.0, ctype);
+            for (INT32 offset = rulesProcessed; offset < (rulesProcessed + rules); offset++)
+            {
+                STRING prefix = L"../UnitTestFiles/GenerateLegendImageConvenience_MultiCTSWithTheme_type";
+                STRING sType;
+                MgUtil::Int32ToString(ctype, sType);
+                prefix += sType;
+                prefix += L"_offset";
+                STRING sOffset;
+                MgUtil::Int32ToString(offset, sOffset);
+                prefix += sOffset;
+
+                STRING fileNamePNG = prefix;
+                fileNamePNG += L"_16x16_PNG.png";
+                Ptr<MgByteReader> rdr = layer->GenerateLegendImage(10000.0, 16, 16, MgImageFormats::Png, 4, offset);
+                Ptr<MgByteSink> sink = new MgByteSink(rdr);
+                sink->ToFile(fileNamePNG);
+
+                STRING fileNamePNG8 = prefix;
+                fileNamePNG8 += L"_16x16_PNG8.png";
+                rdr = layer->GenerateLegendImage(10000.0, 16, 16, MgImageFormats::Png8, 4, offset);
+                sink = new MgByteSink(rdr);
+                sink->ToFile(fileNamePNG8);
+
+                STRING fileNameJPG = prefix;
+                fileNameJPG += L"_16x16_JPG.jpg";
+                rdr = layer->GenerateLegendImage(10000.0, 16, 16, MgImageFormats::Jpeg, 4, offset);
+                sink = new MgByteSink(rdr);
+                sink->ToFile(fileNameJPG);
+
+                STRING fileNameGIF = prefix;
+                fileNameGIF += L"_16x16_JPG.jpg";
+                rdr = layer->GenerateLegendImage(10000.0, 16, 16, MgImageFormats::Gif, 4, offset);
+                sink = new MgByteSink(rdr);
+                sink->ToFile(fileNameGIF);
+            }
+            rulesProcessed += rules;
+        }
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        throw;
+    }
+}
+
+void TestMappingService::TestCase_GetLegendImagePointStyleWithConstRotationsConvenience()
+{
+    try
+    {
+        Ptr<MgResourceIdentifier> mapres = new MgResourceIdentifier(L"Library://UnitTests/Maps/Sheboygan.MapDefinition");
+        Ptr<MgMap> map = new MgMap(m_siteConnection);
+        map->Create(mapres, L"TestCase_GetLegendImageConvenience");
+
+        Ptr<MgResourceIdentifier> ldfId = new MgResourceIdentifier(L"Library://UnitTests/Layers/RotatedPointStyles.LayerDefinition");
+        Ptr<MgLayer> layer = new MgLayer(ldfId, m_svcResource);
+        layer->SetName(L"TestCase_GetLegendImagePointStyleWithConstRotationsConvenience");
+        Ptr<MgLayerCollection> layers = map->GetLayers();
+        layers->Insert(0, layer);
+
+        Ptr<MgIntCollection> types = layer->GetGeometryTypeStyles(1000.0);
+        CPPUNIT_ASSERT(1 == types->GetCount());
+        CPPUNIT_ASSERT(types->IndexOf(1) >= 0);
+        CPPUNIT_ASSERT(types->IndexOf(2) < 0);
+        CPPUNIT_ASSERT(types->IndexOf(3) < 0);
+        CPPUNIT_ASSERT(types->IndexOf(4) < 0);
+
+        CPPUNIT_ASSERT(15 == layer->GetThemeCategoryCount(1000.0, 1));
+        CPPUNIT_ASSERT(-1 == layer->GetThemeCategoryCount(1000.0, 2));
+        CPPUNIT_ASSERT(-1 == layer->GetThemeCategoryCount(1000.0, 3));
+        CPPUNIT_ASSERT(-1 == layer->GetThemeCategoryCount(1000.0, 4));
+        
+        //Do 16x16 icons first. Our common scenario.
+
+        Ptr<MgByteReader> rdr = layer->GenerateLegendImage(1000.0, 16, 16, MgImageFormats::Png, 1, 0);
+        Ptr<MgByteSink> sink = new MgByteSink(rdr);
+        sink->ToFile(L"../UnitTestFiles/RotatedPointConvenience_Square_0_16x16.png");
+        
+        rdr = layer->GenerateLegendImage(1000.0, 16, 16, MgImageFormats::Png, 1, 1);
+        sink = new MgByteSink(rdr);
+        sink->ToFile(L"../UnitTestFiles/RotatedPointConvenience_Square_45_16x16.png");
+
+        rdr = layer->GenerateLegendImage(1000.0, 16, 16, MgImageFormats::Png, 1, 2);
+        sink = new MgByteSink(rdr);
+        sink->ToFile(L"../UnitTestFiles/RotatedPointConvenience_Square_25_16x16.png");
+
+        rdr = layer->GenerateLegendImage(1000.0, 16, 16, MgImageFormats::Png, 1, 3);
+        sink = new MgByteSink(rdr);
+        sink->ToFile(L"../UnitTestFiles/RotatedPointConvenience_Star_0_16x16.png");
+
+        rdr = layer->GenerateLegendImage(1000.0, 16, 16, MgImageFormats::Png, 1, 4);
+        sink = new MgByteSink(rdr);
+        sink->ToFile(L"../UnitTestFiles/RotatedPointConvenience_Star_45_16x16.png");
+
+        rdr = layer->GenerateLegendImage(1000.0, 16, 16, MgImageFormats::Png, 1, 5);
+        sink = new MgByteSink(rdr);
+        sink->ToFile(L"../UnitTestFiles/RotatedPointConvenience_Star_25_16x16.png");
+
+        rdr = layer->GenerateLegendImage(1000.0, 16, 16, MgImageFormats::Png, 1, 6);
+        sink = new MgByteSink(rdr);
+        sink->ToFile(L"../UnitTestFiles/RotatedPointConvenience_Triangle_0_16x16.png");
+
+        rdr = layer->GenerateLegendImage(1000.0, 16, 16, MgImageFormats::Png, 1, 7);
+        sink = new MgByteSink(rdr);
+        sink->ToFile(L"../UnitTestFiles/RotatedPointConvenience_Triangle_45_16x16.png");
+
+        rdr = layer->GenerateLegendImage(1000.0, 16, 16, MgImageFormats::Png, 1, 8);
+        sink = new MgByteSink(rdr);
+        sink->ToFile(L"../UnitTestFiles/RotatedPointConvenience_Triangle_25_16x16.png");
+
+        rdr = layer->GenerateLegendImage(1000.0, 16, 16, MgImageFormats::Png, 1, 9);
+        sink = new MgByteSink(rdr);
+        sink->ToFile(L"../UnitTestFiles/RotatedPointConvenience_Cross_0_16x16.png");
+
+        rdr = layer->GenerateLegendImage(1000.0, 16, 16, MgImageFormats::Png, 1, 10);
+        sink = new MgByteSink(rdr);
+        sink->ToFile(L"../UnitTestFiles/RotatedPointConvenience_Cross_45_16x16.png");
+
+        rdr = layer->GenerateLegendImage(1000.0, 16, 16, MgImageFormats::Png, 1, 11);
+        sink = new MgByteSink(rdr);
+        sink->ToFile(L"../UnitTestFiles/RotatedPointConvenience_Cross_25_16x16.png");
+
+        rdr = layer->GenerateLegendImage(1000.0, 16, 16, MgImageFormats::Png, 1, 12);
+        sink = new MgByteSink(rdr);
+        sink->ToFile(L"../UnitTestFiles/RotatedPointConvenience_XMark_0_16x16.png");
+
+        rdr = layer->GenerateLegendImage(1000.0, 16, 16, MgImageFormats::Png, 1, 13);
+        sink = new MgByteSink(rdr);
+        sink->ToFile(L"../UnitTestFiles/RotatedPointConvenience_XMark_45_16x16.png");
+
+        rdr = layer->GenerateLegendImage(1000.0, 16, 16, MgImageFormats::Png, 1, 14);
+        sink = new MgByteSink(rdr);
+        sink->ToFile(L"../UnitTestFiles/RotatedPointConvenience_XMark_25_16x16.png");
+
+        //Now try 32x16 to see if the rotation handling is acceptable with non-square sizes
+
+        rdr = layer->GenerateLegendImage(1000.0, 32, 16, MgImageFormats::Png, 1, 0);
+        sink = new MgByteSink(rdr);
+        sink->ToFile(L"../UnitTestFiles/RotatedPointConvenience_Square_0_32x16.png");
+
+        rdr = layer->GenerateLegendImage(1000.0, 32, 16, MgImageFormats::Png, 1, 1);
+        sink = new MgByteSink(rdr);
+        sink->ToFile(L"../UnitTestFiles/RotatedPointConvenience_Square_45_32x16.png");
+        
+        rdr = layer->GenerateLegendImage(1000.0, 32, 16, MgImageFormats::Png, 1, 2);
+        sink = new MgByteSink(rdr);
+        sink->ToFile(L"../UnitTestFiles/RotatedPointConvenience_Square_25_32x16.png");
+
+        rdr = layer->GenerateLegendImage(1000.0, 32, 16, MgImageFormats::Png, 1, 3);
+        sink = new MgByteSink(rdr);
+        sink->ToFile(L"../UnitTestFiles/RotatedPointConvenience_Star_0_32x16.png");
+
+        rdr = layer->GenerateLegendImage(1000.0, 32, 16, MgImageFormats::Png, 1, 4);
+        sink = new MgByteSink(rdr);
+        sink->ToFile(L"../UnitTestFiles/RotatedPointConvenience_Star_45_32x16.png");
+
+        rdr = layer->GenerateLegendImage(1000.0, 32, 16, MgImageFormats::Png, 1, 5);
+        sink = new MgByteSink(rdr);
+        sink->ToFile(L"../UnitTestFiles/RotatedPointConvenience_Star_25_32x16.png");
+
+        rdr = layer->GenerateLegendImage(1000.0, 32, 16, MgImageFormats::Png, 1, 6);
+        sink = new MgByteSink(rdr);
+        sink->ToFile(L"../UnitTestFiles/RotatedPointConvenience_Triangle_0_32x16.png");
+
+        rdr = layer->GenerateLegendImage(1000.0, 32, 16, MgImageFormats::Png, 1, 7);
+        sink = new MgByteSink(rdr);
+        sink->ToFile(L"../UnitTestFiles/RotatedPointConvenience_Triangle_45_32x16.png");
+
+        rdr = layer->GenerateLegendImage(1000.0, 32, 16, MgImageFormats::Png, 1, 8);
+        sink = new MgByteSink(rdr);
+        sink->ToFile(L"../UnitTestFiles/RotatedPointConvenience_Triangle_25_32x16.png");
+
+        rdr = layer->GenerateLegendImage(1000.0, 32, 16, MgImageFormats::Png, 1, 9);
+        sink = new MgByteSink(rdr);
+        sink->ToFile(L"../UnitTestFiles/RotatedPointConvenience_Cross_0_32x16.png");
+
+        rdr = layer->GenerateLegendImage(1000.0, 32, 16, MgImageFormats::Png, 1, 10);
+        sink = new MgByteSink(rdr);
+        sink->ToFile(L"../UnitTestFiles/RotatedPointConvenience_Cross_45_32x16.png");
+
+        rdr = layer->GenerateLegendImage(1000.0, 32, 16, MgImageFormats::Png, 1, 11);
+        sink = new MgByteSink(rdr);
+        sink->ToFile(L"../UnitTestFiles/RotatedPointConvenience_Cross_25_32x16.png");
+
+        rdr = layer->GenerateLegendImage(1000.0, 32, 16, MgImageFormats::Png, 1, 12);
+        sink = new MgByteSink(rdr);
+        sink->ToFile(L"../UnitTestFiles/RotatedPointConvenience_XMark_0_32x16.png");
+
+        rdr = layer->GenerateLegendImage(1000.0, 32, 16, MgImageFormats::Png, 1, 13);
+        sink = new MgByteSink(rdr);
+        sink->ToFile(L"../UnitTestFiles/RotatedPointConvenience_XMark_45_32x16.png");
+
+        rdr = layer->GenerateLegendImage(1000.0, 32, 16, MgImageFormats::Png, 1, 14);
+        sink = new MgByteSink(rdr);
+        sink->ToFile(L"../UnitTestFiles/RotatedPointConvenience_XMark_25_32x16.png");
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        throw;
+    }
+}
+
 void TestMappingService::TestCase_QueryFeaturesImageMap()
 {
     try

Modified: trunk/MgDev/Server/src/UnitTesting/TestMappingService.h
===================================================================
--- trunk/MgDev/Server/src/UnitTesting/TestMappingService.h	2014-10-07 09:31:27 UTC (rev 8393)
+++ trunk/MgDev/Server/src/UnitTesting/TestMappingService.h	2014-10-08 01:36:51 UTC (rev 8394)
@@ -34,6 +34,10 @@
     CPPUNIT_TEST(TestCase_GetLegendPlot);
     CPPUNIT_TEST(TestCase_GetLegendImage);
     CPPUNIT_TEST(TestCase_GetLegendImagePointStyleWithConstRotations);
+    CPPUNIT_TEST(TestCase_GetLegendImageConvenience);
+    CPPUNIT_TEST(TestCase_GetLegendImageCompositeConvenience);
+    CPPUNIT_TEST(TestCase_GetLegendImageCompositeThemedConvenience);
+    CPPUNIT_TEST(TestCase_GetLegendImagePointStyleWithConstRotationsConvenience);
     CPPUNIT_TEST(TestCase_CreateRuntimeMap);
     CPPUNIT_TEST(TestCase_DescribeRuntimeMap);
     CPPUNIT_TEST(TestCase_CreateAndDescribeLinkedRuntimeMap);
@@ -65,6 +69,10 @@
     void TestCase_GetLegendPlot();
     void TestCase_GetLegendImage();
     void TestCase_GetLegendImagePointStyleWithConstRotations();
+    void TestCase_GetLegendImageConvenience();
+    void TestCase_GetLegendImageCompositeConvenience();
+    void TestCase_GetLegendImageCompositeThemedConvenience();
+    void TestCase_GetLegendImagePointStyleWithConstRotationsConvenience();
     void TestCase_QueryFeaturesImageMap();
 
 private:

Modified: trunk/MgDev/UnitTest/WebTier/DotNet/MgTestRunner/Program.cs
===================================================================
--- trunk/MgDev/UnitTest/WebTier/DotNet/MgTestRunner/Program.cs	2014-10-07 09:31:27 UTC (rev 8393)
+++ trunk/MgDev/UnitTest/WebTier/DotNet/MgTestRunner/Program.cs	2014-10-08 01:36:51 UTC (rev 8394)
@@ -30,11 +30,20 @@
                 return _siteConn.CreateService(serviceType);
             }
 
-            public MgMapBase CreateMap()
+            public MgMapBase CreateMap(MgResourceIdentifier mapDefinition)
             {
-                return new MgMap(_siteConn);
+                var map = new MgMap(_siteConn);
+                map.Create(mapDefinition, mapDefinition.Name);
+                return map;
             }
 
+            public MgMapBase CreateMap(string coordSys, MgEnvelope env, string name)
+            {
+                var map = new MgMap(_siteConn);
+                map.Create(coordSys, env, name);
+                return map;
+            }
+
             public MgLayerBase CreateLayer(MgResourceIdentifier resId)
             {
                 MgResourceService resSvc = (MgResourceService)_siteConn.CreateService(MgServiceType.ResourceService);

Modified: trunk/MgDev/UnitTest/WebTier/DotNet/TestCommon/CommonTests.cs
===================================================================
--- trunk/MgDev/UnitTest/WebTier/DotNet/TestCommon/CommonTests.cs	2014-10-07 09:31:27 UTC (rev 8393)
+++ trunk/MgDev/UnitTest/WebTier/DotNet/TestCommon/CommonTests.cs	2014-10-08 01:36:51 UTC (rev 8394)
@@ -18,7 +18,8 @@
     public interface IPlatformFactory
     {
         MgService CreateService(int serviceType);
-        MgMapBase CreateMap();
+        MgMapBase CreateMap(MgResourceIdentifier mapDefinition);
+        MgMapBase CreateMap(string coordSys, MgEnvelope env, string name);
         MgLayerBase CreateLayer(MgResourceIdentifier resId);
     }
 

Modified: trunk/MgDev/UnitTest/WebTier/DotNet/TestCommon/ExternalTests/CollectionTests.cs
===================================================================
--- trunk/MgDev/UnitTest/WebTier/DotNet/TestCommon/ExternalTests/CollectionTests.cs	2014-10-07 09:31:27 UTC (rev 8393)
+++ trunk/MgDev/UnitTest/WebTier/DotNet/TestCommon/ExternalTests/CollectionTests.cs	2014-10-08 01:36:51 UTC (rev 8394)
@@ -807,15 +807,14 @@
         {
             string coordsys = "GEOGCS[\"LL84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS 84\",6378137,298.257223563,AUTHORITY[\"EPSG\",\"7030\"]],TOWGS84[0,0,0,0,0,0,0],AUTHORITY[\"EPSG\",\"6326\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.0174532925199433,AUTHORITY[\"EPSG\",\"9108\"]],AXIS[\"Lat\",NORTH],AXIS[\"Long\",EAST],AUTHORITY[\"EPSG\",\"4326\"]]";
             MgEnvelope env = new MgEnvelope(10, 10, 20, 20);
-            MgMapBase map1 = factory.CreateMap();
-            map1.Create(coordsys, env, "map1");
-            MgMapBase map2 = factory.CreateMap();
-            map2.Create(coordsys, env, "map2");
-            MgMapBase map3 = factory.CreateMap();
-            map3.Create(coordsys, env, "map3");
-            MgMapBase map4 = factory.CreateMap();
-            map4.Create(coordsys, env, "map4");
 
+
+
+            MgMapBase map1 = factory.CreateMap(coordsys, env, "map1");
+            MgMapBase map2 = factory.CreateMap(coordsys, env, "map2");
+            MgMapBase map3 = factory.CreateMap(coordsys, env, "map3");
+            MgMapBase map4 = factory.CreateMap(coordsys, env, "map4");
+
             MgMapCollection coll = new MgMapCollection();
             coll.Add(map1);
             coll.Insert(1, map2);

Copied: trunk/MgDev/UnitTest/WebTier/DotNet/TestCommon/ExternalTests/ConvenienceTests.cs (from rev 8268, sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/TestCommon/ExternalTests/ConvenienceTests.cs)
===================================================================
--- trunk/MgDev/UnitTest/WebTier/DotNet/TestCommon/ExternalTests/ConvenienceTests.cs	                        (rev 0)
+++ trunk/MgDev/UnitTest/WebTier/DotNet/TestCommon/ExternalTests/ConvenienceTests.cs	2014-10-08 01:36:51 UTC (rev 8394)
@@ -0,0 +1,1325 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using OSGeo.MapGuide;
+
+namespace OSGeo.MapGuide.Test.Common.ExternalTests
+{
+    public class FeatureServiceTestUtil
+    {
+        public static string CreateTestDataStore(MgResourceIdentifier fsId, string provider, MgFeatureService featSvc)
+        {
+            string scName = "Default";
+            var csFactory = new MgCoordinateSystemFactory();
+            string wkt = csFactory.ConvertCoordinateSystemCodeToWkt("LL84");
+            var schema = new MgFeatureSchema("Default", "Default Schema");
+            var cls = new MgClassDefinition();
+            cls.SetName("Test");
+            var classes = schema.GetClasses();
+            classes.Add(cls);
+
+            var clsProps = cls.GetProperties();
+            var idProps = cls.GetIdentityProperties();
+
+            var id = new MgDataPropertyDefinition("ID");
+            id.SetAutoGeneration(true);
+            id.SetDataType(MgPropertyType.Int32);
+
+            var name = new MgDataPropertyDefinition("Name");
+            name.SetDataType(MgPropertyType.String);
+            name.SetLength(255);
+            name.SetNullable(false);
+
+            var geom = new MgGeometricPropertyDefinition("Geometry");
+            geom.SetGeometryTypes(MgFeatureGeometricType.Point);
+            geom.SetSpatialContextAssociation(scName);
+
+            clsProps.Add(id);
+            clsProps.Add(name);
+            clsProps.Add(geom);
+
+            idProps.Add(id);
+
+            cls.SetDefaultGeometryPropertyName("Geometry");
+
+            var fsp = new MgFileFeatureSourceParams(provider, scName, wkt, schema);
+            featSvc.CreateFeatureSource(fsId, fsp);
+
+            var schemas = featSvc.DescribeSchema(fsId, "");
+            classes = schemas[0].GetClasses();
+            return schemas[0].Name + ":" + classes[0].Name;
+        }
+    }
+
+    public class FeatureServiceInsertFeatures : IExternalTest
+    {
+        public void Execute(IPlatformFactory factory, ITestLogger logger)
+        {
+            var featSvc = (MgFeatureService)factory.CreateService(MgServiceType.FeatureService);
+            var resSvc = (MgResourceService)factory.CreateService(MgServiceType.ResourceService);
+            var fsId = new MgResourceIdentifier("Library://UnitTests/Data/FeatureServiceInsertFeatures.FeatureSource");
+            try
+            {
+                string className = FeatureServiceTestUtil.CreateTestDataStore(fsId, "OSGeo.SDF", featSvc);
+                var agfRw = new MgAgfReaderWriter();
+                var wktRw = new MgWktReaderWriter();
+
+                var props = new MgPropertyCollection();
+                var nameP = new MgStringProperty("Name", "Test");
+                var geom = wktRw.Read("POINT (1 1)");
+                var agf = agfRw.Write(geom);
+                var geomP = new MgGeometryProperty("Geometry", agf);
+                props.Add(nameP);
+                props.Add(geomP);
+
+                var fr = featSvc.InsertFeatures(fsId, className, props);
+                int count = 0;
+                while (fr.ReadNext())
+                {
+                    count++;
+                }
+                fr.Close();
+                Assert.AreEqual(1, count);
+            }
+            finally
+            {
+                resSvc.DeleteResource(fsId);
+            }
+        }
+    }
+
+    public class FeatureServiceInsertFeaturesWithTransaction : IExternalTest
+    {
+        public void Execute(IPlatformFactory factory, ITestLogger logger)
+        {
+            var featSvc = (MgFeatureService)factory.CreateService(MgServiceType.FeatureService);
+            var resSvc = (MgResourceService)factory.CreateService(MgServiceType.ResourceService);
+            var fsId = new MgResourceIdentifier("Library://UnitTests/Data/FeatureServiceInsertFeaturesWithTransaction.FeatureSource");
+            try
+            {
+                string className = FeatureServiceTestUtil.CreateTestDataStore(fsId, "OSGeo.SQLite", featSvc);
+                var agfRw = new MgAgfReaderWriter();
+                var wktRw = new MgWktReaderWriter();
+
+                var props = new MgPropertyCollection();
+                var nameP = new MgStringProperty("Name", "Test");
+                var geom = wktRw.Read("POINT (1 1)");
+                var agf = agfRw.Write(geom);
+                var geomP = new MgGeometryProperty("Geometry", agf);
+                props.Add(nameP);
+                props.Add(geomP);
+                var trans = featSvc.BeginTransaction(fsId);
+                var fr = featSvc.InsertFeatures(fsId, className, props, trans);
+                int count = 0;
+                while (fr.ReadNext())
+                {
+                    count++;
+                }
+                fr.Close();
+                Assert.AreEqual(1, count);
+                trans.Rollback();
+
+                fr = featSvc.SelectFeatures(fsId, className, null);
+                count = 0;
+                while (fr.ReadNext())
+                {
+                    count++;
+                }
+                fr.Close();
+                Assert.AreEqual(0, count);
+            }
+            finally
+            {
+                resSvc.DeleteResource(fsId);
+            }
+        }
+    }
+
+    public class FeatureServiceInsertFeaturesBatched : IExternalTest
+    {
+        public void Execute(IPlatformFactory factory, ITestLogger logger)
+        {
+            var featSvc = (MgFeatureService)factory.CreateService(MgServiceType.FeatureService);
+            var resSvc = (MgResourceService)factory.CreateService(MgServiceType.ResourceService);
+            var fsId = new MgResourceIdentifier("Library://UnitTests/Data/FeatureServiceInsertFeaturesBatched.FeatureSource");
+            try 
+            {
+                string className = FeatureServiceTestUtil.CreateTestDataStore(fsId, "OSGeo.SDF", featSvc);
+                var agfRw = new MgAgfReaderWriter();
+                var wktRw = new MgWktReaderWriter();
+
+                var batchProps = new MgBatchPropertyCollection();
+                for (int i = 0; i < 5; i++)
+                {
+                    var props = new MgPropertyCollection();
+                    var nameP = new MgStringProperty("Name", "Test" + (i + 1));
+                    var geom = wktRw.Read("POINT (1 1)");
+                    var agf = agfRw.Write(geom);
+                    var geomP = new MgGeometryProperty("Geometry", agf);
+                    props.Add(nameP);
+                    props.Add(geomP);
+                    batchProps.Add(props);
+                }
+
+                var fr = featSvc.InsertFeatures(fsId, className, batchProps);
+                int count = 0;
+                while (fr.ReadNext())
+                {
+                    count++;
+                }
+                fr.Close();
+                Assert.AreEqual(5, count);
+            }
+            finally
+            {
+                resSvc.DeleteResource(fsId);
+            }
+        }
+    }
+
+    public class FeatureServiceInsertFeaturesBatchedWithTransaction : IExternalTest
+    {
+        public void Execute(IPlatformFactory factory, ITestLogger logger)
+        {
+            var featSvc = (MgFeatureService)factory.CreateService(MgServiceType.FeatureService);
+            var resSvc = (MgResourceService)factory.CreateService(MgServiceType.ResourceService);
+            var fsId = new MgResourceIdentifier("Library://UnitTests/Data/FeatureServiceInsertFeaturesBatchedWithTransaction.FeatureSource");
+            try
+            {
+                string className = FeatureServiceTestUtil.CreateTestDataStore(fsId, "OSGeo.SQLite", featSvc);
+                var agfRw = new MgAgfReaderWriter();
+                var wktRw = new MgWktReaderWriter();
+
+                var batchProps = new MgBatchPropertyCollection();
+                for (int i = 0; i < 5; i++)
+                {
+                    var props = new MgPropertyCollection();
+                    var nameP = new MgStringProperty("Name", "Test" + (i + 1));
+                    var geom = wktRw.Read("POINT (1 1)");
+                    var agf = agfRw.Write(geom);
+                    var geomP = new MgGeometryProperty("Geometry", agf);
+                    props.Add(nameP);
+                    props.Add(geomP);
+                    batchProps.Add(props);
+                }
+
+                var trans = featSvc.BeginTransaction(fsId);
+                var fr = featSvc.InsertFeatures(fsId, className, batchProps, trans);
+                int count = 0;
+                while (fr.ReadNext())
+                {
+                    count++;
+                }
+                fr.Close();
+                Assert.AreEqual(5, count);
+                trans.Rollback();
+
+                fr = featSvc.SelectFeatures(fsId, className, null);
+                count = 0;
+                while (fr.ReadNext())
+                {
+                    count++;
+                }
+                fr.Close();
+                Assert.AreEqual(0, count);
+            }
+            finally
+            {
+                resSvc.DeleteResource(fsId);
+            }
+        }
+    }
+
+    public class FeatureServiceUpdateFeatures : IExternalTest
+    {
+        public void Execute(IPlatformFactory factory, ITestLogger logger)
+        {
+            var featSvc = (MgFeatureService)factory.CreateService(MgServiceType.FeatureService);
+            var resSvc = (MgResourceService)factory.CreateService(MgServiceType.ResourceService);
+            var fsId = new MgResourceIdentifier("Library://UnitTests/Data/FeatureServiceUpdateFeatures.FeatureSource");
+            try
+            {
+                string className = FeatureServiceTestUtil.CreateTestDataStore(fsId, "OSGeo.SDF", featSvc);
+                var agfRw = new MgAgfReaderWriter();
+                var wktRw = new MgWktReaderWriter();
+
+                var batchProps = new MgBatchPropertyCollection();
+                for (int i = 0; i < 5; i++)
+                {
+                    var props = new MgPropertyCollection();
+                    var nameP = new MgStringProperty("Name", "Test" + (i + 1));
+                    var geom = wktRw.Read("POINT (1 1)");
+                    var agf = agfRw.Write(geom);
+                    var geomP = new MgGeometryProperty("Geometry", agf);
+                    props.Add(nameP);
+                    props.Add(geomP);
+                    batchProps.Add(props);
+                }
+
+                var fr = featSvc.InsertFeatures(fsId, className, batchProps);
+                int count = 0;
+                while (fr.ReadNext())
+                {
+                    count++;
+                }
+                fr.Close();
+                Assert.AreEqual(5, count);
+
+                var updateProps = new MgPropertyCollection();
+                var newName = new MgStringProperty("Name", "Test3Updated");
+                updateProps.Add(newName);
+
+                int updated = featSvc.UpdateMatchingFeatures(fsId, className, updateProps, "Name = 'Test3'");
+                Assert.AreEqual(1, updated);
+            }
+            finally
+            {
+                resSvc.DeleteResource(fsId);
+            }
+        }
+    }
+
+    public class FeatureServiceUpdateFeaturesWithTransaction : IExternalTest
+    {
+        public void Execute(IPlatformFactory factory, ITestLogger logger)
+        {
+            var featSvc = (MgFeatureService)factory.CreateService(MgServiceType.FeatureService);
+            var resSvc = (MgResourceService)factory.CreateService(MgServiceType.ResourceService);
+            var fsId = new MgResourceIdentifier("Library://UnitTests/Data/FeatureServiceUpdateFeaturesWithTransaction.FeatureSource");
+            try
+            {
+                string className = FeatureServiceTestUtil.CreateTestDataStore(fsId, "OSGeo.SQLite", featSvc);
+                var agfRw = new MgAgfReaderWriter();
+                var wktRw = new MgWktReaderWriter();
+
+                var batchProps = new MgBatchPropertyCollection();
+                for (int i = 0; i < 5; i++)
+                {
+                    var props = new MgPropertyCollection();
+                    var nameP = new MgStringProperty("Name", "Test" + (i + 1));
+                    var geom = wktRw.Read("POINT (1 1)");
+                    var agf = agfRw.Write(geom);
+                    var geomP = new MgGeometryProperty("Geometry", agf);
+                    props.Add(nameP);
+                    props.Add(geomP);
+                    batchProps.Add(props);
+                }
+
+                var fr = featSvc.InsertFeatures(fsId, className, batchProps);
+                int count = 0;
+                while (fr.ReadNext())
+                {
+                    count++;
+                }
+                fr.Close();
+                Assert.AreEqual(5, count);
+
+                var updateProps = new MgPropertyCollection();
+                var newName = new MgStringProperty("Name", "Test3Updated");
+                updateProps.Add(newName);
+
+                var trans = featSvc.BeginTransaction(fsId);
+                int updated = featSvc.UpdateMatchingFeatures(fsId, className, updateProps, "Name = 'Test3'", trans);
+                Assert.AreEqual(1, updated);
+                trans.Rollback();
+
+                var query = new MgFeatureQueryOptions();
+                query.SetFilter("Name = 'Test3Updated'");
+                fr = featSvc.SelectFeatures(fsId, className, query);
+                count = 0;
+                while (fr.ReadNext())
+                {
+                    count++;
+                }
+                fr.Close();
+                Assert.AreEqual(0, count);
+            }
+            finally
+            {
+                resSvc.DeleteResource(fsId);
+            }
+        }
+    }
+
+    public class FeatureServiceDeleteFeatures : IExternalTest
+    {
+        public void Execute(IPlatformFactory factory, ITestLogger logger)
+        {
+            var featSvc = (MgFeatureService)factory.CreateService(MgServiceType.FeatureService);
+            var resSvc = (MgResourceService)factory.CreateService(MgServiceType.ResourceService);
+            var fsId = new MgResourceIdentifier("Library://UnitTests/Data/FeatureServiceDeleteFeatures.FeatureSource");
+            try
+            {
+                string className = FeatureServiceTestUtil.CreateTestDataStore(fsId, "OSGeo.SDF", featSvc);
+                var agfRw = new MgAgfReaderWriter();
+                var wktRw = new MgWktReaderWriter();
+
+                var batchProps = new MgBatchPropertyCollection();
+                for (int i = 0; i < 5; i++)
+                {
+                    var props = new MgPropertyCollection();
+                    var nameP = new MgStringProperty("Name", "Test" + (i + 1));
+                    var geom = wktRw.Read("POINT (1 1)");
+                    var agf = agfRw.Write(geom);
+                    var geomP = new MgGeometryProperty("Geometry", agf);
+                    props.Add(nameP);
+                    props.Add(geomP);
+                    batchProps.Add(props);
+                }
+
+                var fr = featSvc.InsertFeatures(fsId, className, batchProps);
+                int count = 0;
+                while (fr.ReadNext())
+                {
+                    count++;
+                }
+                fr.Close();
+                Assert.AreEqual(5, count);
+
+                int deleted = featSvc.DeleteFeatures(fsId, className, "Name = 'Test3'");
+                Assert.AreEqual(1, deleted);
+
+                var query = new MgFeatureQueryOptions();
+                fr = featSvc.SelectFeatures(fsId, className, query);
+                count = 0;
+                while (fr.ReadNext())
+                {
+                    count++;
+                }
+                fr.Close();
+                Assert.AreEqual(4, count);
+
+                query.SetFilter("Name = 'Test3'");
+                fr = featSvc.SelectFeatures(fsId, className, query);
+                count = 0;
+                while (fr.ReadNext())
+                {
+                    count++;
+                }
+                fr.Close();
+                Assert.AreEqual(0, count);
+            }
+            finally
+            {
+                resSvc.DeleteResource(fsId);
+            }
+        }
+    }
+
+    public class FeatureServiceDeleteFeaturesWithTransaction : IExternalTest
+    {
+        public void Execute(IPlatformFactory factory, ITestLogger logger)
+        {
+            var featSvc = (MgFeatureService)factory.CreateService(MgServiceType.FeatureService);
+            var resSvc = (MgResourceService)factory.CreateService(MgServiceType.ResourceService);
+            var fsId = new MgResourceIdentifier("Library://UnitTests/Data/FeatureServiceDeleteFeaturesWithTransaction.FeatureSource");
+            try
+            {
+                string className = FeatureServiceTestUtil.CreateTestDataStore(fsId, "OSGeo.SQLite", featSvc);
+                var agfRw = new MgAgfReaderWriter();
+                var wktRw = new MgWktReaderWriter();
+
+                var batchProps = new MgBatchPropertyCollection();
+                for (int i = 0; i < 5; i++)
+                {
+                    var props = new MgPropertyCollection();
+                    var nameP = new MgStringProperty("Name", "Test" + (i + 1));
+                    var geom = wktRw.Read("POINT (1 1)");
+                    var agf = agfRw.Write(geom);
+                    var geomP = new MgGeometryProperty("Geometry", agf);
+                    props.Add(nameP);
+                    props.Add(geomP);
+                    batchProps.Add(props);
+                }
+
+                var fr = featSvc.InsertFeatures(fsId, className, batchProps);
+                int count = 0;
+                while (fr.ReadNext())
+                {
+                    count++;
+                }
+                fr.Close();
+                Assert.AreEqual(5, count);
+
+                var trans = featSvc.BeginTransaction(fsId);
+                int deleted = featSvc.DeleteFeatures(fsId, className, "Name = 'Test3'", trans);
+                Assert.AreEqual(1, deleted);
+
+                var query = new MgFeatureQueryOptions();
+                fr = featSvc.SelectFeatures(fsId, className, query);
+                count = 0;
+                while (fr.ReadNext())
+                {
+                    count++;
+                }
+                fr.Close();
+                Assert.AreEqual(4, count);
+                trans.Rollback();
+
+                query.SetFilter("Name = 'Test3'");
+                fr = featSvc.SelectFeatures(fsId, className, query);
+                count = 0;
+                while (fr.ReadNext())
+                {
+                    count++;
+                }
+                fr.Close();
+                Assert.AreEqual(1, count);
+            }
+            finally
+            {
+                resSvc.DeleteResource(fsId);
+            }
+        }
+    }
+
+    public class LayerInsertFeatures : IExternalTest
+    {
+        public void Execute(IPlatformFactory factory, ITestLogger logger)
+        {
+            var resSvc = (MgResourceService)factory.CreateService(MgServiceType.ResourceService);
+            var featSvc = (MgFeatureService)factory.CreateService(MgServiceType.FeatureService);
+            var fsId = new MgResourceIdentifier("Library://UnitTests/Data/LayerInsertFeatures.FeatureSource");
+            try
+            {
+                string className = FeatureServiceTestUtil.CreateTestDataStore(fsId, "OSGeo.SDF", featSvc);
+
+                MgCoordinateSystemFactory csFactory = new MgCoordinateSystemFactory();
+                MgMapBase map = factory.CreateMap(csFactory.ConvertCoordinateSystemCodeToWkt("LL84"), new MgEnvelope(-180, -90, 180, 90), "TestMap");
+                MgLayerCollection layers = map.GetLayers();
+
+                string layerXml = string.Format(Properties.Resources.TestLayer, fsId.ToString(), className, "Geometry");
+                byte[] bytes = Encoding.UTF8.GetBytes(layerXml);
+                MgByteSource bs = new MgByteSource(bytes, bytes.Length);
+                MgByteReader br = bs.GetReader();
+
+                var ldfId = new MgResourceIdentifier("Library://UnitTests/Layers/TestLayer.LayerDefinition");
+                resSvc.SetResource(ldfId, br, null);
+
+                MgLayerBase layer = factory.CreateLayer(ldfId);
+                layers.Insert(0, layer);
+
+                var agfRw = new MgAgfReaderWriter();
+                var wktRw = new MgWktReaderWriter();
+
+                var props = new MgPropertyCollection();
+                var nameP = new MgStringProperty("Name", "Test");
+                var geom = wktRw.Read("POINT (1 1)");
+                var agf = agfRw.Write(geom);
+                var geomP = new MgGeometryProperty("Geometry", agf);
+                props.Add(nameP);
+                props.Add(geomP);
+
+                var fr = layer.InsertFeatures(props, null);
+                int count = 0;
+                while (fr.ReadNext())
+                {
+                    count++;
+                }
+                fr.Close();
+                Assert.AreEqual(1, count);
+
+                var query = new MgFeatureQueryOptions();
+                fr = layer.SelectFeatures(query);
+                count = 0;
+                while (fr.ReadNext())
+                {
+                    count++;
+                }
+                fr.Close();
+                Assert.AreEqual(1, count);
+            }
+            finally
+            {
+                resSvc.DeleteResource(fsId);
+            }
+        }
+    }
+
+    public class LayerInsertFeaturesWithTransaction : IExternalTest
+    {
+        public void Execute(IPlatformFactory factory, ITestLogger logger)
+        {
+            var resSvc = (MgResourceService)factory.CreateService(MgServiceType.ResourceService);
+            var featSvc = (MgFeatureService)factory.CreateService(MgServiceType.FeatureService);
+            var fsId = new MgResourceIdentifier("Library://UnitTests/Data/LayerInsertFeaturesWithTransaction.FeatureSource");
+            try
+            {
+                string className = FeatureServiceTestUtil.CreateTestDataStore(fsId, "OSGeo.SQLite", featSvc);
+
+                MgCoordinateSystemFactory csFactory = new MgCoordinateSystemFactory();
+                MgMapBase map = factory.CreateMap(csFactory.ConvertCoordinateSystemCodeToWkt("LL84"), new MgEnvelope(-180, -90, 180, 90), "TestMap");
+                MgLayerCollection layers = map.GetLayers();
+
+                string layerXml = string.Format(Properties.Resources.TestLayer, fsId.ToString(), className, "Geometry");
+                byte[] bytes = Encoding.UTF8.GetBytes(layerXml);
+                MgByteSource bs = new MgByteSource(bytes, bytes.Length);
+                MgByteReader br = bs.GetReader();
+
+                var ldfId = new MgResourceIdentifier("Library://UnitTests/Layers/TestLayer.LayerDefinition");
+                resSvc.SetResource(ldfId, br, null);
+
+                MgLayerBase layer = factory.CreateLayer(ldfId);
+                layers.Insert(0, layer);
+
+                var agfRw = new MgAgfReaderWriter();
+                var wktRw = new MgWktReaderWriter();
+
+                var props = new MgPropertyCollection();
+                var nameP = new MgStringProperty("Name", "Test");
+                var geom = wktRw.Read("POINT (1 1)");
+                var agf = agfRw.Write(geom);
+                var geomP = new MgGeometryProperty("Geometry", agf);
+                props.Add(nameP);
+                props.Add(geomP);
+
+                var trans = layer.BeginTransaction();
+                var fr = layer.InsertFeatures(props, trans);
+                int count = 0;
+                while (fr.ReadNext())
+                {
+                    count++;
+                }
+                fr.Close();
+                Assert.AreEqual(1, count);
+                trans.Rollback();
+
+                var query = new MgFeatureQueryOptions();
+                fr = layer.SelectFeatures(query);
+                count = 0;
+                while (fr.ReadNext())
+                {
+                    count++;
+                }
+                fr.Close();
+                Assert.AreEqual(0, count);
+            }
+            finally
+            {
+                resSvc.DeleteResource(fsId);
+            }
+        }
+    }
+
+    public class LayerInsertFeaturesBatched : IExternalTest
+    {
+        public void Execute(IPlatformFactory factory, ITestLogger logger)
+        {
+            var resSvc = (MgResourceService)factory.CreateService(MgServiceType.ResourceService);
+            var featSvc = (MgFeatureService)factory.CreateService(MgServiceType.FeatureService);
+            var fsId = new MgResourceIdentifier("Library://UnitTests/Data/LayerInsertFeaturesBatched.FeatureSource");
+            try
+            {
+                string className = FeatureServiceTestUtil.CreateTestDataStore(fsId, "OSGeo.SDF", featSvc);
+
+                MgCoordinateSystemFactory csFactory = new MgCoordinateSystemFactory();
+                MgMapBase map = factory.CreateMap(csFactory.ConvertCoordinateSystemCodeToWkt("LL84"), new MgEnvelope(-180, -90, 180, 90), "TestMap");
+                MgLayerCollection layers = map.GetLayers();
+
+                string layerXml = string.Format(Properties.Resources.TestLayer, fsId.ToString(), className, "Geometry");
+                byte[] bytes = Encoding.UTF8.GetBytes(layerXml);
+                MgByteSource bs = new MgByteSource(bytes, bytes.Length);
+                MgByteReader br = bs.GetReader();
+
+                var ldfId = new MgResourceIdentifier("Library://UnitTests/Layers/TestLayer.LayerDefinition");
+                resSvc.SetResource(ldfId, br, null);
+
+                MgLayerBase layer = factory.CreateLayer(ldfId);
+                layers.Insert(0, layer);
+
+                var agfRw = new MgAgfReaderWriter();
+                var wktRw = new MgWktReaderWriter();
+
+                var batchProps = new MgBatchPropertyCollection();
+                for (int i = 0; i < 5; i++)
+                {
+                    var props = new MgPropertyCollection();
+                    var nameP = new MgStringProperty("Name", "Test" + (i + 1));
+                    var geom = wktRw.Read("POINT (1 1)");
+                    var agf = agfRw.Write(geom);
+                    var geomP = new MgGeometryProperty("Geometry", agf);
+                    props.Add(nameP);
+                    props.Add(geomP);
+                    batchProps.Add(props);
+                }
+
+                var fr = layer.InsertFeatures(batchProps, null);
+                int count = 0;
+                while (fr.ReadNext())
+                {
+                    count++;
+                }
+                fr.Close();
+                Assert.AreEqual(5, count);
+
+                var query = new MgFeatureQueryOptions();
+                fr = layer.SelectFeatures(query);
+                count = 0;
+                while (fr.ReadNext())
+                {
+                    count++;
+                }
+                fr.Close();
+                Assert.AreEqual(5, count);
+            }
+            finally
+            {
+                resSvc.DeleteResource(fsId);
+            }
+        }
+    }
+
+    public class LayerInsertFeaturesBatchedWithTransaction : IExternalTest
+    {
+        public void Execute(IPlatformFactory factory, ITestLogger logger)
+        {
+            var resSvc = (MgResourceService)factory.CreateService(MgServiceType.ResourceService);
+            var featSvc = (MgFeatureService)factory.CreateService(MgServiceType.FeatureService);
+            var fsId = new MgResourceIdentifier("Library://UnitTests/Data/LayerInsertFeaturesBatchedWithTransaction.FeatureSource");
+            try
+            {
+                string className = FeatureServiceTestUtil.CreateTestDataStore(fsId, "OSGeo.SQLite", featSvc);
+
+                MgCoordinateSystemFactory csFactory = new MgCoordinateSystemFactory();
+                MgMapBase map = factory.CreateMap(csFactory.ConvertCoordinateSystemCodeToWkt("LL84"), new MgEnvelope(-180, -90, 180, 90), "TestMap");
+                MgLayerCollection layers = map.GetLayers();
+
+                string layerXml = string.Format(Properties.Resources.TestLayer, fsId.ToString(), className, "Geometry");
+                byte[] bytes = Encoding.UTF8.GetBytes(layerXml);
+                MgByteSource bs = new MgByteSource(bytes, bytes.Length);
+                MgByteReader br = bs.GetReader();
+
+                var ldfId = new MgResourceIdentifier("Library://UnitTests/Layers/TestLayer.LayerDefinition");
+                resSvc.SetResource(ldfId, br, null);
+
+                MgLayerBase layer = factory.CreateLayer(ldfId);
+                layers.Insert(0, layer);
+
+                var agfRw = new MgAgfReaderWriter();
+                var wktRw = new MgWktReaderWriter();
+
+                var batchProps = new MgBatchPropertyCollection();
+                for (int i = 0; i < 5; i++)
+                {
+                    var props = new MgPropertyCollection();
+                    var nameP = new MgStringProperty("Name", "Test" + (i + 1));
+                    var geom = wktRw.Read("POINT (1 1)");
+                    var agf = agfRw.Write(geom);
+                    var geomP = new MgGeometryProperty("Geometry", agf);
+                    props.Add(nameP);
+                    props.Add(geomP);
+                    batchProps.Add(props);
+                }
+
+                var trans = layer.BeginTransaction();
+                var fr = layer.InsertFeatures(batchProps, trans);
+                int count = 0;
+                while (fr.ReadNext())
+                {
+                    count++;
+                }
+                fr.Close();
+                Assert.AreEqual(5, count);
+                trans.Rollback();
+
+                var query = new MgFeatureQueryOptions();
+                fr = layer.SelectFeatures(query);
+                count = 0;
+                while (fr.ReadNext())
+                {
+                    count++;
+                }
+                fr.Close();
+                Assert.AreEqual(0, count);
+            }
+            finally
+            {
+                resSvc.DeleteResource(fsId);
+            }
+        }
+    }
+
+    public class LayerUpdateFeatures : IExternalTest
+    {
+        public void Execute(IPlatformFactory factory, ITestLogger logger)
+        {
+            var resSvc = (MgResourceService)factory.CreateService(MgServiceType.ResourceService);
+            var featSvc = (MgFeatureService)factory.CreateService(MgServiceType.FeatureService);
+            var fsId = new MgResourceIdentifier("Library://UnitTests/Data/LayerUpdateFeatures.FeatureSource");
+            try
+            {
+                string className = FeatureServiceTestUtil.CreateTestDataStore(fsId, "OSGeo.SDF", featSvc);
+
+                MgCoordinateSystemFactory csFactory = new MgCoordinateSystemFactory();
+                MgMapBase map = factory.CreateMap(csFactory.ConvertCoordinateSystemCodeToWkt("LL84"), new MgEnvelope(-180, -90, 180, 90), "TestMap");
+                MgLayerCollection layers = map.GetLayers();
+
+                string layerXml = string.Format(Properties.Resources.TestLayer, fsId.ToString(), className, "Geometry");
+                byte[] bytes = Encoding.UTF8.GetBytes(layerXml);
+                MgByteSource bs = new MgByteSource(bytes, bytes.Length);
+                MgByteReader br = bs.GetReader();
+
+                var ldfId = new MgResourceIdentifier("Library://UnitTests/Layers/TestLayer.LayerDefinition");
+                resSvc.SetResource(ldfId, br, null);
+
+                MgLayerBase layer = factory.CreateLayer(ldfId);
+                layers.Insert(0, layer);
+
+                var agfRw = new MgAgfReaderWriter();
+                var wktRw = new MgWktReaderWriter();
+
+                var batchProps = new MgBatchPropertyCollection();
+                for (int i = 0; i < 5; i++)
+                {
+                    var props = new MgPropertyCollection();
+                    var nameP = new MgStringProperty("Name", "Test" + (i + 1));
+                    var geom = wktRw.Read("POINT (1 1)");
+                    var agf = agfRw.Write(geom);
+                    var geomP = new MgGeometryProperty("Geometry", agf);
+                    props.Add(nameP);
+                    props.Add(geomP);
+                    batchProps.Add(props);
+                }
+
+                var fr = layer.InsertFeatures(batchProps, null);
+                int count = 0;
+                while (fr.ReadNext())
+                {
+                    count++;
+                }
+                fr.Close();
+                Assert.AreEqual(5, count);
+
+                var updateProps = new MgPropertyCollection();
+                var newName = new MgStringProperty("Name", "Test3Updated");
+                updateProps.Add(newName);
+
+                int updated = layer.UpdateMatchingFeatures(updateProps, "Name = 'Test3'", null);
+                Assert.AreEqual(1, updated);
+            }
+            finally
+            {
+                resSvc.DeleteResource(fsId);
+            }
+        }
+    }
+
+    public class LayerUpdateFeaturesWithTransaction : IExternalTest
+    {
+        public void Execute(IPlatformFactory factory, ITestLogger logger)
+        {
+            var resSvc = (MgResourceService)factory.CreateService(MgServiceType.ResourceService);
+            var featSvc = (MgFeatureService)factory.CreateService(MgServiceType.FeatureService);
+            var fsId = new MgResourceIdentifier("Library://UnitTests/Data/LayerUpdateFeaturesWithTransaction.FeatureSource");
+            try
+            {
+                string className = FeatureServiceTestUtil.CreateTestDataStore(fsId, "OSGeo.SQLite", featSvc);
+
+                MgCoordinateSystemFactory csFactory = new MgCoordinateSystemFactory();
+                MgMapBase map = factory.CreateMap(csFactory.ConvertCoordinateSystemCodeToWkt("LL84"), new MgEnvelope(-180, -90, 180, 90), "TestMap");
+                MgLayerCollection layers = map.GetLayers();
+
+                string layerXml = string.Format(Properties.Resources.TestLayer, fsId.ToString(), className, "Geometry");
+                byte[] bytes = Encoding.UTF8.GetBytes(layerXml);
+                MgByteSource bs = new MgByteSource(bytes, bytes.Length);
+                MgByteReader br = bs.GetReader();
+
+                var ldfId = new MgResourceIdentifier("Library://UnitTests/Layers/TestLayer.LayerDefinition");
+                resSvc.SetResource(ldfId, br, null);
+
+                MgLayerBase layer = factory.CreateLayer(ldfId);
+                layers.Insert(0, layer);
+
+                var agfRw = new MgAgfReaderWriter();
+                var wktRw = new MgWktReaderWriter();
+
+                var batchProps = new MgBatchPropertyCollection();
+                for (int i = 0; i < 5; i++)
+                {
+                    var props = new MgPropertyCollection();
+                    var nameP = new MgStringProperty("Name", "Test" + (i + 1));
+                    var geom = wktRw.Read("POINT (1 1)");
+                    var agf = agfRw.Write(geom);
+                    var geomP = new MgGeometryProperty("Geometry", agf);
+                    props.Add(nameP);
+                    props.Add(geomP);
+                    batchProps.Add(props);
+                }
+
+                var fr = layer.InsertFeatures(batchProps, null);
+                int count = 0;
+                while (fr.ReadNext())
+                {
+                    count++;
+                }
+                fr.Close();
+                Assert.AreEqual(5, count);
+
+                var updateProps = new MgPropertyCollection();
+                var newName = new MgStringProperty("Name", "Test3Updated");
+                updateProps.Add(newName);
+
+                var trans = layer.BeginTransaction();
+                int updated = layer.UpdateMatchingFeatures(updateProps, "Name = 'Test3'", trans);
+                Assert.AreEqual(1, updated);
+
+                trans.Rollback();
+                var query = new MgFeatureQueryOptions();
+                query.SetFilter("Name = 'Test3Updated'");
+                fr = layer.SelectFeatures(query);
+                count = 0;
+                while (fr.ReadNext())
+                {
+                    count++;
+                }
+                fr.Close();
+                Assert.AreEqual(0, count);
+            }
+            finally
+            {
+                resSvc.DeleteResource(fsId);
+            }
+        }
+    }
+
+    public class LayerDeleteFeatures : IExternalTest
+    {
+        public void Execute(IPlatformFactory factory, ITestLogger logger)
+        {
+            var resSvc = (MgResourceService)factory.CreateService(MgServiceType.ResourceService);
+            var featSvc = (MgFeatureService)factory.CreateService(MgServiceType.FeatureService);
+            var fsId = new MgResourceIdentifier("Library://UnitTests/Data/LayerDeleteFeatures.FeatureSource");
+            try
+            {
+                string className = FeatureServiceTestUtil.CreateTestDataStore(fsId, "OSGeo.SDF", featSvc);
+
+                MgCoordinateSystemFactory csFactory = new MgCoordinateSystemFactory();
+                MgMapBase map = factory.CreateMap(csFactory.ConvertCoordinateSystemCodeToWkt("LL84"), new MgEnvelope(-180, -90, 180, 90), "TestMap");
+                MgLayerCollection layers = map.GetLayers();
+
+                string layerXml = string.Format(Properties.Resources.TestLayer, fsId.ToString(), className, "Geometry");
+                byte[] bytes = Encoding.UTF8.GetBytes(layerXml);
+                MgByteSource bs = new MgByteSource(bytes, bytes.Length);
+                MgByteReader br = bs.GetReader();
+
+                var ldfId = new MgResourceIdentifier("Library://UnitTests/Layers/TestLayer.LayerDefinition");
+                resSvc.SetResource(ldfId, br, null);
+
+                MgLayerBase layer = factory.CreateLayer(ldfId);
+                layers.Insert(0, layer);
+
+                var agfRw = new MgAgfReaderWriter();
+                var wktRw = new MgWktReaderWriter();
+
+                var batchProps = new MgBatchPropertyCollection();
+                for (int i = 0; i < 5; i++)
+                {
+                    var props = new MgPropertyCollection();
+                    var nameP = new MgStringProperty("Name", "Test" + (i + 1));
+                    var geom = wktRw.Read("POINT (1 1)");
+                    var agf = agfRw.Write(geom);
+                    var geomP = new MgGeometryProperty("Geometry", agf);
+                    props.Add(nameP);
+                    props.Add(geomP);
+                    batchProps.Add(props);
+                }
+
+                var fr = layer.InsertFeatures(batchProps, null);
+                int count = 0;
+                while (fr.ReadNext())
+                {
+                    count++;
+                }
+                fr.Close();
+                Assert.AreEqual(5, count);
+
+                int deleted = layer.DeleteFeatures("Name = 'Test3'", null);
+                Assert.AreEqual(1, deleted);
+
+                var query = new MgFeatureQueryOptions();
+                fr = layer.SelectFeatures(query);
+                count = 0;
+                while (fr.ReadNext())
+                {
+                    count++;
+                }
+                fr.Close();
+                Assert.AreEqual(4, count);
+
+                query.SetFilter("Name = 'Test3'");
+                fr = layer.SelectFeatures(query);
+                count = 0;
+                while (fr.ReadNext())
+                {
+                    count++;
+                }
+                fr.Close();
+                Assert.AreEqual(0, count);
+            }
+            finally
+            {
+                resSvc.DeleteResource(fsId);
+            }
+        }
+    }
+
+    public class LayerDeleteFeaturesWithTransaction : IExternalTest
+    {
+        public void Execute(IPlatformFactory factory, ITestLogger logger)
+        {
+            var resSvc = (MgResourceService)factory.CreateService(MgServiceType.ResourceService);
+            var featSvc = (MgFeatureService)factory.CreateService(MgServiceType.FeatureService);
+            var fsId = new MgResourceIdentifier("Library://UnitTests/Data/LayerDeleteFeaturesWithTransaction.FeatureSource");
+            try
+            {
+                string className = FeatureServiceTestUtil.CreateTestDataStore(fsId, "OSGeo.SQLite", featSvc);
+
+                MgCoordinateSystemFactory csFactory = new MgCoordinateSystemFactory();
+                MgMapBase map = factory.CreateMap(csFactory.ConvertCoordinateSystemCodeToWkt("LL84"), new MgEnvelope(-180, -90, 180, 90), "TestMap");
+                MgLayerCollection layers = map.GetLayers();
+
+                string layerXml = string.Format(Properties.Resources.TestLayer, fsId.ToString(), className, "Geometry");
+                byte[] bytes = Encoding.UTF8.GetBytes(layerXml);
+                MgByteSource bs = new MgByteSource(bytes, bytes.Length);
+                MgByteReader br = bs.GetReader();
+
+                var ldfId = new MgResourceIdentifier("Library://UnitTests/Layers/TestLayer.LayerDefinition");
+                resSvc.SetResource(ldfId, br, null);
+
+                MgLayerBase layer = factory.CreateLayer(ldfId);
+                layers.Insert(0, layer);
+
+                var agfRw = new MgAgfReaderWriter();
+                var wktRw = new MgWktReaderWriter();
+
+                var batchProps = new MgBatchPropertyCollection();
+                for (int i = 0; i < 5; i++)
+                {
+                    var props = new MgPropertyCollection();
+                    var nameP = new MgStringProperty("Name", "Test" + (i + 1));
+                    var geom = wktRw.Read("POINT (1 1)");
+                    var agf = agfRw.Write(geom);
+                    var geomP = new MgGeometryProperty("Geometry", agf);
+                    props.Add(nameP);
+                    props.Add(geomP);
+                    batchProps.Add(props);
+                }
+
+                var fr = layer.InsertFeatures(batchProps, null);
+                int count = 0;
+                while (fr.ReadNext())
+                {
+                    count++;
+                }
+                fr.Close();
+                Assert.AreEqual(5, count);
+
+                var trans = layer.BeginTransaction();
+                int deleted = layer.DeleteFeatures("Name = 'Test3'", trans);
+                Assert.AreEqual(1, deleted);
+                trans.Rollback();
+
+                var query = new MgFeatureQueryOptions();
+                fr = layer.SelectFeatures(query);
+                count = 0;
+                while (fr.ReadNext())
+                {
+                    count++;
+                }
+                fr.Close();
+                Assert.AreEqual(5, count);
+
+                query.SetFilter("Name = 'Test3'");
+                fr = layer.SelectFeatures(query);
+                count = 0;
+                while (fr.ReadNext())
+                {
+                    count++;
+                }
+                fr.Close();
+                Assert.AreEqual(1, count);
+            }
+            finally
+            {
+                resSvc.DeleteResource(fsId);
+            }
+        }
+    }
+
+    public class SelectFeaturesWithTransform : IExternalTest
+    {
+        public void Execute(IPlatformFactory factory, ITestLogger logger)
+        {
+            var featSvc = (MgFeatureService)factory.CreateService(MgServiceType.FeatureService);
+            var resSvc = (MgResourceService)factory.CreateService(MgServiceType.ResourceService);
+            var fsId = new MgResourceIdentifier("Library://UnitTests/Data/TransformTest.FeatureSource");
+            try
+            {
+                //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);
+                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();
+            }
+            finally
+            {
+                resSvc.DeleteResource(fsId);
+            }
+        }
+    }
+
+    public class LayerSelectFeaturesWithTransform : IExternalTest
+    {
+        public void Execute(IPlatformFactory factory, ITestLogger logger)
+        {
+            var featSvc = (MgFeatureService)factory.CreateService(MgServiceType.FeatureService);
+            var resSvc = (MgResourceService)factory.CreateService(MgServiceType.ResourceService);
+            var fsId = new MgResourceIdentifier("Library://UnitTests/Data/TransformTest.FeatureSource");
+            try
+            {
+                //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);
+
+                featSvc.CreateFeatureSource(fsId, create);
+
+                MgMapBase map = factory.CreateMap(srcWkt, new MgEnvelope(-180, -90, 180, 90), "TestMap");
+                MgLayerCollection layers = map.GetLayers();
+
+                string layerXml = string.Format(Properties.Resources.TestLayer, fsId.ToString(), "Default:Test", "Geometry");
+                byte[] bytes = Encoding.UTF8.GetBytes(layerXml);
+                MgByteSource bs = new MgByteSource(bytes, bytes.Length);
+                MgByteReader br = bs.GetReader();
+
+                var ldfId = new MgResourceIdentifier("Library://UnitTests/Layers/TestLayer.LayerDefinition");
+                resSvc.SetResource(ldfId, br, null);
+
+                MgLayerBase layer = factory.CreateLayer(ldfId);
+                layers.Insert(0, layer);
+
+                //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 = layer.InsertFeatures(propVals, null);
+                fr.Close();
+
+                MgCoordinate coord2 = geomFact.CreateCoordinateXY(-37.2020, 144.2020);
+                MgPoint pt2 = geomFact.CreatePoint(coord2);
+                MgByteReader agf2 = agfRw.Write(pt2);
+
+                pGeom.SetValue(agf2);
+                fr = layer.InsertFeatures(propVals, null);
+                fr.Close();
+
+                //Now select from this data store
+                MgFeatureQueryOptions query = new MgFeatureQueryOptions();
+                MgReader reader = layer.SelectFeatures(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();
+            }
+            finally
+            {
+                resSvc.DeleteResource(fsId);
+            }
+        }
+    }
+
+    public class LayerGetSpatialContexts : IExternalTest
+    {
+        public void Execute(IPlatformFactory factory, ITestLogger logger)
+        {
+            var resSvc = (MgResourceService)factory.CreateService(MgServiceType.ResourceService);
+            var featSvc = (MgFeatureService)factory.CreateService(MgServiceType.FeatureService);
+            var fsId = new MgResourceIdentifier("Library://UnitTests/Data/GetSpatialContexts.FeatureSource");
+            try
+            {
+                string className = FeatureServiceTestUtil.CreateTestDataStore(fsId, "OSGeo.SDF", featSvc);
+
+                MgCoordinateSystemFactory csFactory = new MgCoordinateSystemFactory();
+                MgMapBase map = factory.CreateMap(csFactory.ConvertCoordinateSystemCodeToWkt("LL84"), new MgEnvelope(-180, -90, 180, 90), "TestMap");
+                MgLayerCollection layers = map.GetLayers();
+
+                string layerXml = string.Format(Properties.Resources.TestLayer, fsId.ToString(), className, "Geometry");
+                byte[] bytes = Encoding.UTF8.GetBytes(layerXml);
+                MgByteSource bs = new MgByteSource(bytes, bytes.Length);
+                MgByteReader br = bs.GetReader();
+
+                var ldfId = new MgResourceIdentifier("Library://UnitTests/Layers/TestLayer.LayerDefinition");
+                resSvc.SetResource(ldfId, br, null);
+
+                MgLayerBase layer = factory.CreateLayer(ldfId);
+                layers.Insert(0, layer);
+
+                MgSpatialContextReader scReader = layer.GetSpatialContexts(false);
+                int count = 0;
+                try
+                {
+                    while (scReader.ReadNext())
+                    {
+                        Assert.AreEqual("Default", scReader.GetName());
+                        Assert.AreEqual(csFactory.ConvertCoordinateSystemCodeToWkt("LL84"), scReader.GetCoordinateSystemWkt());
+                        count++;
+                    }
+                }
+                finally
+                {
+                    scReader.Close();
+                }
+                Assert.AreEqual(1, count);
+            }
+            finally
+            {
+                resSvc.DeleteResource(fsId);
+            }
+        }
+    }
+}

Modified: trunk/MgDev/UnitTest/WebTier/DotNet/TestCommon/ExternalTests/PropertiesTest.cs
===================================================================
--- trunk/MgDev/UnitTest/WebTier/DotNet/TestCommon/ExternalTests/PropertiesTest.cs	2014-10-07 09:31:27 UTC (rev 8393)
+++ trunk/MgDev/UnitTest/WebTier/DotNet/TestCommon/ExternalTests/PropertiesTest.cs	2014-10-08 01:36:51 UTC (rev 8394)
@@ -369,7 +369,7 @@
     {
         public void Execute(IPlatformFactory factory, ITestLogger logger)
         {
-            MgMapBase mb = factory.CreateMap();
+            MgMapBase mb = new MgMapBase();
             Assert.AreEqual("", mb.Name);
             Assert.AreEqual("", mb.SessionId);
             Assert.IsNull(mb.MapDefinition);

Copied: trunk/MgDev/UnitTest/WebTier/DotNet/TestCommon/Properties/Resources.Designer.cs (from rev 8268, sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/TestCommon/Properties/Resources.Designer.cs)
===================================================================
--- trunk/MgDev/UnitTest/WebTier/DotNet/TestCommon/Properties/Resources.Designer.cs	                        (rev 0)
+++ trunk/MgDev/UnitTest/WebTier/DotNet/TestCommon/Properties/Resources.Designer.cs	2014-10-08 01:36:51 UTC (rev 8394)
@@ -0,0 +1,92 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+//     This code was generated by a tool.
+//     Runtime Version:4.0.30319.18444
+//
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace OSGeo.MapGuide.Test.Common.Properties {
+    using System;
+    
+    
+    /// <summary>
+    ///   A strongly-typed resource class, for looking up localized strings, etc.
+    /// </summary>
+    // This class was auto-generated by the StronglyTypedResourceBuilder
+    // class via a tool like ResGen or Visual Studio.
+    // To add or remove a member, edit your .ResX file then rerun ResGen
+    // with the /str option, or rebuild your VS project.
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+    internal class Resources {
+        
+        private static global::System.Resources.ResourceManager resourceMan;
+        
+        private static global::System.Globalization.CultureInfo resourceCulture;
+        
+        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+        internal Resources() {
+        }
+        
+        /// <summary>
+        ///   Returns the cached ResourceManager instance used by this class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Resources.ResourceManager ResourceManager {
+            get {
+                if (object.ReferenceEquals(resourceMan, null)) {
+                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("OSGeo.MapGuide.Test.Common.Properties.Resources", typeof(Resources).Assembly);
+                    resourceMan = temp;
+                }
+                return resourceMan;
+            }
+        }
+        
+        /// <summary>
+        ///   Overrides the current thread's CurrentUICulture property for all
+        ///   resource lookups using this strongly typed resource class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Globalization.CultureInfo Culture {
+            get {
+                return resourceCulture;
+            }
+            set {
+                resourceCulture = value;
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to .
+        /// </summary>
+        internal static string TestLayer {
+            get {
+                return ResourceManager.GetString("TestLayer", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to <?xml version="1.0" encoding="utf-8"?>
+        ///<MapDefinition xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" version="2.4.0" xsi:noNamespaceSchemaLocation="MapDefinition-2.4.0.xsd">
+        ///  <Name>Test Map</Name>
+        ///  <CoordinateSystem>{0}</CoordinateSystem>
+        ///  <Extents>
+        ///    <MinX>{1}</MinX>
+        ///    <MaxX>{2}</MaxX>
+        ///    <MinY>{3}</MinY>
+        ///    <MaxY>{4}</MaxY>
+        ///  </Extents>
+        ///  <BackgroundColor>ffffffff</BackgroundColor>
+        ///</MapDefinition>.
+        /// </summary>
+        internal static string TestMapDef {
+            get {
+                return ResourceManager.GetString("TestMapDef", resourceCulture);
+            }
+        }
+    }
+}

Copied: trunk/MgDev/UnitTest/WebTier/DotNet/TestCommon/Properties/Resources.resx (from rev 8268, sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/TestCommon/Properties/Resources.resx)
===================================================================
--- trunk/MgDev/UnitTest/WebTier/DotNet/TestCommon/Properties/Resources.resx	                        (rev 0)
+++ trunk/MgDev/UnitTest/WebTier/DotNet/TestCommon/Properties/Resources.resx	2014-10-08 01:36:51 UTC (rev 8394)
@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
+  <data name="TestLayer" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>..\Resources\TestLayer.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
+  </data>
+  <data name="TestMapDef" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>..\Resources\TestMapDef.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
+  </data>
+</root>
\ No newline at end of file

Modified: trunk/MgDev/UnitTest/WebTier/DotNet/TestCommon/TestCommon.csproj
===================================================================
--- trunk/MgDev/UnitTest/WebTier/DotNet/TestCommon/TestCommon.csproj	2014-10-07 09:31:27 UTC (rev 8393)
+++ trunk/MgDev/UnitTest/WebTier/DotNet/TestCommon/TestCommon.csproj	2014-10-08 01:36:51 UTC (rev 8394)
@@ -76,6 +76,7 @@
     <Compile Include="CommonTests.cs" />
     <Compile Include="ExternalTests\ByteReaderTest.cs" />
     <Compile Include="ExternalTests\CollectionTests.cs" />
+    <Compile Include="ExternalTests\ConvenienceTests.cs" />
     <Compile Include="ExternalTests\PropertiesTest.cs" />
     <Compile Include="FeatureService\Operations.cs" />
     <Compile Include="ITestExecutor.cs" />
@@ -86,6 +87,11 @@
     <Compile Include="PlatformApiTestExecutor.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="FeatureService\FeatureServiceOperationExecutor.cs" />
+    <Compile Include="Properties\Resources.Designer.cs">
+      <AutoGen>True</AutoGen>
+      <DesignTime>True</DesignTime>
+      <DependentUpon>Resources.resx</DependentUpon>
+    </Compile>
     <Compile Include="ResourceService\ResourceServiceOperationExecutor.cs" />
     <Compile Include="ResourceService\Operations.cs" />
     <Compile Include="SqliteException.cs" />
@@ -95,7 +101,18 @@
     <Compile Include="UnitTestException.cs" />
     <Compile Include="CommonUtility.cs" />
   </ItemGroup>
-  <ItemGroup />
+  <ItemGroup>
+    <EmbeddedResource Include="Properties\Resources.resx">
+      <Generator>ResXFileCodeGenerator</Generator>
+      <LastGenOutput>Resources.Designer.cs</LastGenOutput>
+    </EmbeddedResource>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="Resources\TestLayer.txt" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="Resources\TestMapDef.txt" />
+  </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <PropertyGroup>
     <PreBuildEvent>call "$(SolutionDir)prebuild.bat" "$(ConfigurationName)" "$(PlatformName)"</PreBuildEvent>

Modified: trunk/MgDev/UnitTest/WebTier/DotNet/TestMapGuideApi/ExternalTests/CollectionTests.cs
===================================================================
--- trunk/MgDev/UnitTest/WebTier/DotNet/TestMapGuideApi/ExternalTests/CollectionTests.cs	2014-10-07 09:31:27 UTC (rev 8393)
+++ trunk/MgDev/UnitTest/WebTier/DotNet/TestMapGuideApi/ExternalTests/CollectionTests.cs	2014-10-08 01:36:51 UTC (rev 8394)
@@ -13,15 +13,10 @@
         {
             string coordsys = "GEOGCS[\"LL84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS 84\",6378137,298.257223563,AUTHORITY[\"EPSG\",\"7030\"]],TOWGS84[0,0,0,0,0,0,0],AUTHORITY[\"EPSG\",\"6326\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.0174532925199433,AUTHORITY[\"EPSG\",\"9108\"]],AXIS[\"Lat\",NORTH],AXIS[\"Long\",EAST],AUTHORITY[\"EPSG\",\"4326\"]]";
             MgEnvelope env = new MgEnvelope(10, 10, 20, 20);
-            MgMap map1 = (MgMap)factory.CreateMap();
-            map1.Create(coordsys, env, "map1");
+            MgMap map1 = (MgMap)factory.CreateMap(coordsys, env, "map1");
+            MgMap map2 = (MgMap)factory.CreateMap(coordsys, env, "map2");
+            MgMap map3 = (MgMap)factory.CreateMap(coordsys, env, "map3");
 
-            MgMap map2 = (MgMap)factory.CreateMap();
-            map2.Create(coordsys, env, "map2");
-
-            MgMap map3 = (MgMap)factory.CreateMap();
-            map3.Create(coordsys, env, "map3");
-
             MgPlotSpecification spec = new MgPlotSpecification((float)8.0, (float)11.0, "in", (float)0.0, (float)0.0, (float)5.0, (float)5.0);
             MgResourceIdentifier resId = new MgResourceIdentifier("Library://test.WebLayout");
             MgLayout layout1 = new MgLayout(resId, "Title1", "in");

Copied: trunk/MgDev/UnitTest/WebTier/DotNet/TestMapGuideApi/ExternalTests/ResourceServiceTests.cs (from rev 8363, sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/TestMapGuideApi/ExternalTests/ResourceServiceTests.cs)
===================================================================
--- trunk/MgDev/UnitTest/WebTier/DotNet/TestMapGuideApi/ExternalTests/ResourceServiceTests.cs	                        (rev 0)
+++ trunk/MgDev/UnitTest/WebTier/DotNet/TestMapGuideApi/ExternalTests/ResourceServiceTests.cs	2014-10-08 01:36:51 UTC (rev 8394)
@@ -0,0 +1,66 @@
+using OSGeo.MapGuide.Test.Common;
+using OSGeo.MapGuide.Test.Common.ExternalTests;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace OSGeo.MapGuide.Test.Web.ExternalTests
+{
+    public class ResourceMetadataTest : IExternalTest
+    {
+        public void Execute(IPlatformFactory factory, ITestLogger logger)
+        {
+            var resSvc = (MgResourceService)factory.CreateService(MgServiceType.ResourceService);
+            var featSvc = (MgFeatureService)factory.CreateService(MgServiceType.FeatureService);
+            var fsId = new MgResourceIdentifier("Library://UnitTests/Data/Metadata.FeatureSource");
+            try
+            {
+                if (resSvc.ResourceExists(fsId))
+                    resSvc.DeleteResource(fsId);
+
+                string metadata = resSvc.EnumerateResourceDocuments(null, MgResourceType.FeatureSource, MgResourceHeaderProperties.Metadata);
+                File.WriteAllText("metadata.txt", metadata);
+
+                string className = FeatureServiceTestUtil.CreateTestDataStore(fsId, "OSGeo.SDF", featSvc);
+                string headerXml = string.Format(Properties.Resources.ResourceHeaderTemplate, "Foo", "Bar");
+                var bytes = Encoding.UTF8.GetBytes(headerXml);
+                var source = new MgByteSource(bytes, bytes.Length);
+                var rdr = source.GetReader();
+
+                resSvc.SetResource(fsId, null, rdr);
+                string metadata2 = resSvc.EnumerateResourceDocuments(null, MgResourceType.FeatureSource, MgResourceHeaderProperties.Metadata);
+                File.WriteAllText("metadata2.txt", metadata2);
+
+                Assert.IsFalse(metadata == metadata2);
+            }
+            finally
+            {
+                if (resSvc.ResourceExists(fsId))
+                    resSvc.DeleteResource(fsId);
+            }
+        }
+    }
+
+    public class ResourceModifiedTest : IExternalTest
+    {
+        public void Execute(IPlatformFactory factory, ITestLogger logger)
+        {
+            var resSvc = (MgResourceService)factory.CreateService(MgServiceType.ResourceService);
+            var featSvc = (MgFeatureService)factory.CreateService(MgServiceType.FeatureService);
+            MgResourceIdentifier fsId = new MgResourceIdentifier("Library://UnitTests/Data/Timestamp.FeatureSource");
+            string className = FeatureServiceTestUtil.CreateTestDataStore(fsId, "OSGeo.SDF", featSvc);
+            MgByteReader content = resSvc.GetResourceContent(fsId);
+            MgDateTime mod1 = resSvc.GetResourceModifiedDate(fsId);
+            Thread.Sleep(1500);
+            resSvc.SetResource(fsId, content, null);
+            MgDateTime mod2 = resSvc.GetResourceModifiedDate(fsId);
+
+            Assert.IsFalse(mod1.ToString() == mod2.ToString());
+        }
+    }
+
+}

Copied: trunk/MgDev/UnitTest/WebTier/DotNet/TestMapGuideApi/Properties/Resources.Designer.cs (from rev 8363, sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/TestMapGuideApi/Properties/Resources.Designer.cs)
===================================================================
--- trunk/MgDev/UnitTest/WebTier/DotNet/TestMapGuideApi/Properties/Resources.Designer.cs	                        (rev 0)
+++ trunk/MgDev/UnitTest/WebTier/DotNet/TestMapGuideApi/Properties/Resources.Designer.cs	2014-10-08 01:36:51 UTC (rev 8394)
@@ -0,0 +1,85 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+//     This code was generated by a tool.
+//     Runtime Version:4.0.30319.18444
+//
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace OSGeo.MapGuide.Test.Web.Properties {
+    using System;
+    
+    
+    /// <summary>
+    ///   A strongly-typed resource class, for looking up localized strings, etc.
+    /// </summary>
+    // This class was auto-generated by the StronglyTypedResourceBuilder
+    // class via a tool like ResGen or Visual Studio.
+    // To add or remove a member, edit your .ResX file then rerun ResGen
+    // with the /str option, or rebuild your VS project.
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+    internal class Resources {
+        
+        private static global::System.Resources.ResourceManager resourceMan;
+        
+        private static global::System.Globalization.CultureInfo resourceCulture;
+        
+        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+        internal Resources() {
+        }
+        
+        /// <summary>
+        ///   Returns the cached ResourceManager instance used by this class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Resources.ResourceManager ResourceManager {
+            get {
+                if (object.ReferenceEquals(resourceMan, null)) {
+                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("OSGeo.MapGuide.Test.Web.Properties.Resources", typeof(Resources).Assembly);
+                    resourceMan = temp;
+                }
+                return resourceMan;
+            }
+        }
+        
+        /// <summary>
+        ///   Overrides the current thread's CurrentUICulture property for all
+        ///   resource lookups using this strongly typed resource class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Globalization.CultureInfo Culture {
+            get {
+                return resourceCulture;
+            }
+            set {
+                resourceCulture = value;
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to <?xml version="1.0"?>
+        ///<ResourceDocumentHeader xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xsi:noNamespaceSchemaLocation="ResourceDocumentHeader-1.0.0.xsd">
+        ///  <Security>
+        ///    <Inherited>true</Inherited>
+        ///  </Security>
+        ///  <Metadata>
+        ///    <Simple>
+        ///	  <Property>
+        ///	    <Name>{0}</Name>
+        ///		<Value>{1}</Value>
+        ///	  </Property>
+        ///	</Simple>
+        ///  </Metadata>
+        ///</ResourceDocumentHeader>.
+        /// </summary>
+        internal static string ResourceHeaderTemplate {
+            get {
+                return ResourceManager.GetString("ResourceHeaderTemplate", resourceCulture);
+            }
+        }
+    }
+}

Copied: trunk/MgDev/UnitTest/WebTier/DotNet/TestMapGuideApi/Properties/Resources.resx (from rev 8363, sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/TestMapGuideApi/Properties/Resources.resx)
===================================================================
--- trunk/MgDev/UnitTest/WebTier/DotNet/TestMapGuideApi/Properties/Resources.resx	                        (rev 0)
+++ trunk/MgDev/UnitTest/WebTier/DotNet/TestMapGuideApi/Properties/Resources.resx	2014-10-08 01:36:51 UTC (rev 8394)
@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
+  <data name="ResourceHeaderTemplate" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>..\Resources\ResourceHeaderTemplate.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
+  </data>
+</root>
\ No newline at end of file

Modified: trunk/MgDev/UnitTest/WebTier/DotNet/TestMapGuideApi/TestMapGuideApi.csproj
===================================================================
--- trunk/MgDev/UnitTest/WebTier/DotNet/TestMapGuideApi/TestMapGuideApi.csproj	2014-10-07 09:31:27 UTC (rev 8393)
+++ trunk/MgDev/UnitTest/WebTier/DotNet/TestMapGuideApi/TestMapGuideApi.csproj	2014-10-08 01:36:51 UTC (rev 8394)
@@ -80,10 +80,16 @@
     <Compile Include="DrawingService\DrawingServiceOperationExecutor.cs" />
     <Compile Include="DrawingService\Operations.cs" />
     <Compile Include="ExternalTests\CollectionTests.cs" />
+    <Compile Include="ExternalTests\ResourceServiceTests.cs" />
     <Compile Include="MapGuideTests.cs" />
     <Compile Include="MappingService\MappingServiceOperationExecutor.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="MapGuideTestExecutorCollection.cs" />
+    <Compile Include="Properties\Resources.Designer.cs">
+      <AutoGen>True</AutoGen>
+      <DesignTime>True</DesignTime>
+      <DependentUpon>Resources.resx</DependentUpon>
+    </Compile>
     <Compile Include="RenderingService\RenderingServiceOperationExecutor.cs" />
     <Compile Include="ServerAdmin\Operations.cs" />
     <Compile Include="ServerAdmin\ServerAdminOperationExecutor.cs" />
@@ -98,7 +104,15 @@
       <Name>TestCommon</Name>
     </ProjectReference>
   </ItemGroup>
-  <ItemGroup />
+  <ItemGroup>
+    <EmbeddedResource Include="Properties\Resources.resx">
+      <Generator>ResXFileCodeGenerator</Generator>
+      <LastGenOutput>Resources.Designer.cs</LastGenOutput>
+    </EmbeddedResource>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="Resources\ResourceHeaderTemplate.txt" />
+  </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <PropertyGroup>
     <PreBuildEvent>call "$(SolutionDir)prebuild.bat" "$(ConfigurationName)" "$(PlatformName)"</PreBuildEvent>

Modified: trunk/MgDev/Web/src/DotNetUnmanagedApi/PlatformBase/PlatformBaseConstants.xml
===================================================================
--- trunk/MgDev/Web/src/DotNetUnmanagedApi/PlatformBase/PlatformBaseConstants.xml	2014-10-07 09:31:27 UTC (rev 8393)
+++ trunk/MgDev/Web/src/DotNetUnmanagedApi/PlatformBase/PlatformBaseConstants.xml	2014-10-08 01:36:51 UTC (rev 8394)
@@ -72,6 +72,7 @@
   <Class name="MgResourceDataName" />
   <Class name="MgResourceDataType" />
   <Class name="MgResourcePermission" />
+  <Class name="MgResourceHeaderProperties" />
   <Class name="MgLayerGroupType" />
   <Class name="MgLayerType" />
   <Class name="MgFeatureGeometricType" />

Modified: trunk/MgDev/Web/src/MapGuideApi/Constants.xml
===================================================================
--- trunk/MgDev/Web/src/MapGuideApi/Constants.xml	2014-10-07 09:31:27 UTC (rev 8393)
+++ trunk/MgDev/Web/src/MapGuideApi/Constants.xml	2014-10-08 01:36:51 UTC (rev 8394)
@@ -75,6 +75,7 @@
   <Class name="MgResourceDataName" />
   <Class name="MgResourceDataType" />
   <Class name="MgResourcePermission" />
+  <Class name="MgResourceHeaderProperties" />
   <Class name="MgMimeType" />
   <Class name="MgPropertyType" />
   <Class name="MgPageUnitsType" />



More information about the mapguide-commits mailing list