[mapguide-commits] r8264 - in sandbox/jng/convenience_apis: Common/MapGuideCommon/MapLayer Common/MapGuideCommon/Services Common/PlatformBase/MapLayer Common/PlatformBase/Services 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/TestCommon/Resources UnitTest/WebTier/DotNet/TestMapGuideApi/ExternalTests

svn_mapguide at osgeo.org svn_mapguide at osgeo.org
Thu Jun 26 04:37:30 PDT 2014


Author: jng
Date: 2014-06-26 04:37:30 -0700 (Thu, 26 Jun 2014)
New Revision: 8264

Added:
   sandbox/jng/convenience_apis/Server/src/Services/Feature/OpDeleteFeatures.cpp
   sandbox/jng/convenience_apis/Server/src/Services/Feature/OpDeleteFeatures.h
   sandbox/jng/convenience_apis/Server/src/Services/Feature/OpInsertFeatures.cpp
   sandbox/jng/convenience_apis/Server/src/Services/Feature/OpInsertFeatures.h
   sandbox/jng/convenience_apis/Server/src/Services/Feature/OpInsertFeaturesBatched.cpp
   sandbox/jng/convenience_apis/Server/src/Services/Feature/OpInsertFeaturesBatched.h
   sandbox/jng/convenience_apis/Server/src/Services/Feature/OpUpdateMatchingFeatures.cpp
   sandbox/jng/convenience_apis/Server/src/Services/Feature/OpUpdateMatchingFeatures.h
   sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/TestCommon/ExternalTests/ConvenienceTests.cs
   sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/TestCommon/Properties/Resources.Designer.cs
   sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/TestCommon/Properties/Resources.resx
   sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/TestCommon/Resources/
   sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/TestCommon/Resources/TestLayer.txt
   sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/TestCommon/Resources/TestMapDef.txt
Modified:
   sandbox/jng/convenience_apis/Common/MapGuideCommon/MapLayer/Layer.cpp
   sandbox/jng/convenience_apis/Common/MapGuideCommon/MapLayer/Layer.h
   sandbox/jng/convenience_apis/Common/MapGuideCommon/Services/ProxyFeatureService.cpp
   sandbox/jng/convenience_apis/Common/MapGuideCommon/Services/ProxyFeatureService.h
   sandbox/jng/convenience_apis/Common/PlatformBase/MapLayer/LayerBase.cpp
   sandbox/jng/convenience_apis/Common/PlatformBase/MapLayer/LayerBase.h
   sandbox/jng/convenience_apis/Common/PlatformBase/Services/FeatureDefs.h
   sandbox/jng/convenience_apis/Common/PlatformBase/Services/FeatureService.h
   sandbox/jng/convenience_apis/Server/src/Services/Feature/FeatureOperationFactory.cpp
   sandbox/jng/convenience_apis/Server/src/Services/Feature/ServerFeatureService.cpp
   sandbox/jng/convenience_apis/Server/src/Services/Feature/ServerFeatureService.h
   sandbox/jng/convenience_apis/Server/src/Services/Feature/ServerFeatureService.vcxproj
   sandbox/jng/convenience_apis/Server/src/Services/Feature/ServerFeatureService.vcxproj.filters
   sandbox/jng/convenience_apis/Server/src/Services/Feature/ServerFeatureServiceBuild.cpp
   sandbox/jng/convenience_apis/Server/src/UnitTesting/TestFeatureService.cpp
   sandbox/jng/convenience_apis/Server/src/UnitTesting/TestFeatureService.h
   sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/MgTestRunner/Program.cs
   sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/TestCommon/CommonTests.cs
   sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/TestCommon/ExternalTests/CollectionTests.cs
   sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/TestCommon/ExternalTests/PropertiesTest.cs
   sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/TestCommon/TestCommon.csproj
   sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/TestMapGuideApi/ExternalTests/CollectionTests.cs
Log:
Add new convenience APIs to MgFeatureService and MgLayerBase:

 * InsertFeatures - Inserts one or more features to the specified feature source
 * UpdateMatchingFeatures - Updates one or more features in the specified feature source
 * DeleteFeatures - Deletes one or more features in the specified feature source

These APIs are much simpler to use than UpdateFeatures and require less boilerplate and have simpler exception handling logic (all of the above APIs *will* throw exceptions on any error, transactional or not).

Use the external test mechanism introduced in the previous submission to add new .net tests to exercise these new convenience APIs

Modified: sandbox/jng/convenience_apis/Common/MapGuideCommon/MapLayer/Layer.cpp
===================================================================
--- sandbox/jng/convenience_apis/Common/MapGuideCommon/MapLayer/Layer.cpp	2014-06-25 15:30:06 UTC (rev 8263)
+++ sandbox/jng/convenience_apis/Common/MapGuideCommon/MapLayer/Layer.cpp	2014-06-26 11:37:30 UTC (rev 8264)
@@ -307,6 +307,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 +349,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 +379,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 +434,111 @@
         m_idProps.push_back(idProp);
     }
 }
+
+MgFeatureReader* MgLayer::InsertFeatures(MgPropertyCollection* properties)
+{
+    Ptr<MgFeatureService> featureService = dynamic_cast<MgFeatureService*>(
+        GetMap()->GetService(MgServiceType::FeatureService));
+    Ptr<MgResourceIdentifier> resourceId = new MgResourceIdentifier(m_featureSourceId);
+
+    Ptr<MgFeatureReader> ret;
+    Ptr<MgTransaction> trans;
+    MG_TRY()
+
+    if (UseTransaction(featureService, GetProviderName()))
+        trans = featureService->BeginTransaction(resourceId);
+
+    ret = featureService->InsertFeatures(resourceId, m_featureName, properties);
+    if (NULL != trans.p)
+        trans->Commit();
+
+    MG_CATCH(L"MgLayer.InsertFeatures")
+
+    if (NULL != trans.p)
+        trans->Rollback();
+
+    MG_THROW()
+
+    return ret.Detach();
+}
+
+MgFeatureReader* MgLayer::InsertFeatures(MgBatchPropertyCollection* properties)
+{
+    Ptr<MgFeatureService> featureService = dynamic_cast<MgFeatureService*>(
+        GetMap()->GetService(MgServiceType::FeatureService));
+    Ptr<MgResourceIdentifier> resourceId = new MgResourceIdentifier(m_featureSourceId);
+
+    Ptr<MgFeatureReader> ret;
+    Ptr<MgTransaction> trans;
+    MG_TRY()
+
+    if (UseTransaction(featureService, GetProviderName()))
+        trans = featureService->BeginTransaction(resourceId);
+
+    ret = featureService->InsertFeatures(resourceId, m_featureName, properties);
+    if (NULL != trans.p)
+        trans->Commit();
+
+    MG_CATCH(L"MgLayer.InsertFeatures")
+
+    if (NULL != trans.p)
+        trans->Rollback();
+
+    MG_THROW()
+
+    return ret.Detach();
+}
+
+INT32 MgLayer::UpdateMatchingFeatures(MgPropertyCollection* properties, CREFSTRING filter)
+{
+    Ptr<MgFeatureService> featureService = dynamic_cast<MgFeatureService*>(
+        GetMap()->GetService(MgServiceType::FeatureService));
+    Ptr<MgResourceIdentifier> resourceId = new MgResourceIdentifier(m_featureSourceId);
+
+    INT32 updated = -1;
+    Ptr<MgTransaction> trans;
+    MG_TRY()
+
+    if (UseTransaction(featureService, GetProviderName()))
+        trans = featureService->BeginTransaction(resourceId);
+
+    updated = featureService->UpdateMatchingFeatures(resourceId, m_featureName, properties, filter);
+    if (NULL != trans.p)
+        trans->Commit();
+
+    MG_CATCH(L"MgLayer.UpdateMatchingFeatures")
+
+    if (NULL != trans.p)
+        trans->Rollback();
+
+    MG_THROW()
+
+    return updated;
+}
+
+INT32 MgLayer::DeleteFeatures(CREFSTRING filter)
+{
+    Ptr<MgFeatureService> featureService = dynamic_cast<MgFeatureService*>(
+        GetMap()->GetService(MgServiceType::FeatureService));
+    Ptr<MgResourceIdentifier> resourceId = new MgResourceIdentifier(m_featureSourceId);
+
+    INT32 deleted = -1;
+    Ptr<MgTransaction> trans;
+    MG_TRY()
+
+    if (UseTransaction(featureService, GetProviderName()))
+        trans = featureService->BeginTransaction(resourceId);
+
+    deleted = featureService->DeleteFeatures(resourceId, m_featureName, filter);
+    if (NULL != trans.p)
+        trans->Commit();
+
+    MG_CATCH(L"MgLayer.DeleteFeatures")
+
+    if (NULL != trans.p)
+        trans->Rollback();
+
+    MG_THROW()
+
+    return deleted;
+}

Modified: sandbox/jng/convenience_apis/Common/MapGuideCommon/MapLayer/Layer.h
===================================================================
--- sandbox/jng/convenience_apis/Common/MapGuideCommon/MapLayer/Layer.h	2014-06-25 15:30:06 UTC (rev 8263)
+++ sandbox/jng/convenience_apis/Common/MapGuideCommon/MapLayer/Layer.h	2014-06-26 11:37:30 UTC (rev 8264)
@@ -224,6 +224,143 @@
     ///
     virtual MgPropertyCollection* UpdateFeatures(MgFeatureCommandCollection* commands);
 
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    /// \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
+    ///
+    /// \return
+    /// Returns a feature reader object that contains the set of properties 
+    /// inserted into the datastore by the insert command.
+    ///
+    /// \remarks
+    /// Transactions will be used internally if the provider supports them.
+    /// 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);
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    /// \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
+    ///
+    /// \return
+    /// Returns a feature reader object that contains the set of properties 
+    /// inserted into the datastore by the insert command.
+    ///
+    /// \remarks
+    /// Transactions will be used internally if the provider supports them.
+    /// 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);
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Updates all features that match the given filter with the specified property values
+    ///
+    /// \remarks
+    /// Transactions will be used internally if the provider supports them
+    ///
+    /// <!-- 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
+    ///
+    /// \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);
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    /// \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
+    ///
+    /// \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);
+
 INTERNAL_API:
 
     //////////////////////////////////////////////////////////////////
@@ -308,6 +445,8 @@
     }
 
 private:
+    STRING GetProviderName();
+    bool UseTransaction(MgFeatureService* svcFeature, CREFSTRING providerName);
 
     MgMapBase* GetMap();
 

Modified: sandbox/jng/convenience_apis/Common/MapGuideCommon/Services/ProxyFeatureService.cpp
===================================================================
--- sandbox/jng/convenience_apis/Common/MapGuideCommon/Services/ProxyFeatureService.cpp	2014-06-25 15:30:06 UTC (rev 8263)
+++ sandbox/jng/convenience_apis/Common/MapGuideCommon/Services/ProxyFeatureService.cpp	2014-06-26 11:37:30 UTC (rev 8264)
@@ -1897,3 +1897,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: sandbox/jng/convenience_apis/Common/MapGuideCommon/Services/ProxyFeatureService.h
===================================================================
--- sandbox/jng/convenience_apis/Common/MapGuideCommon/Services/ProxyFeatureService.h	2014-06-25 15:30:06 UTC (rev 8263)
+++ sandbox/jng/convenience_apis/Common/MapGuideCommon/Services/ProxyFeatureService.h	2014-06-26 11:37:30 UTC (rev 8264)
@@ -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: sandbox/jng/convenience_apis/Common/PlatformBase/MapLayer/LayerBase.cpp
===================================================================
--- sandbox/jng/convenience_apis/Common/PlatformBase/MapLayer/LayerBase.cpp	2014-06-25 15:30:06 UTC (rev 8263)
+++ sandbox/jng/convenience_apis/Common/PlatformBase/MapLayer/LayerBase.cpp	2014-06-26 11:37:30 UTC (rev 8264)
@@ -799,3 +799,27 @@
     throw new MgNotImplementedException(L"MgLayerBase.UpdateFeatures",
         __LINE__, __WFILE__, NULL, L"", NULL);
 }
+
+MgFeatureReader* MgLayerBase::InsertFeatures(MgPropertyCollection* properties)
+{
+    throw new MgNotImplementedException(L"MgLayerBase.InsertFeatures",
+        __LINE__, __WFILE__, NULL, L"", NULL);
+}
+
+MgFeatureReader* MgLayerBase::InsertFeatures(MgBatchPropertyCollection* properties)
+{
+    throw new MgNotImplementedException(L"MgLayerBase.InsertFeatures",
+        __LINE__, __WFILE__, NULL, L"", NULL);
+}
+
+INT32 MgLayerBase::UpdateMatchingFeatures(MgPropertyCollection* properties, CREFSTRING filter)
+{
+    throw new MgNotImplementedException(L"MgLayerBase.UpdateMatchingFeatures",
+        __LINE__, __WFILE__, NULL, L"", NULL);
+}
+
+INT32 MgLayerBase::DeleteFeatures(CREFSTRING filter)
+{
+    throw new MgNotImplementedException(L"MgLayerBase.DeleteFeatures",
+        __LINE__, __WFILE__, NULL, L"", NULL);
+}

Modified: sandbox/jng/convenience_apis/Common/PlatformBase/MapLayer/LayerBase.h
===================================================================
--- sandbox/jng/convenience_apis/Common/PlatformBase/MapLayer/LayerBase.h	2014-06-25 15:30:06 UTC (rev 8263)
+++ sandbox/jng/convenience_apis/Common/PlatformBase/MapLayer/LayerBase.h	2014-06-26 11:37:30 UTC (rev 8264)
@@ -870,6 +870,143 @@
     /// \since 1.2
     virtual MgPropertyCollection* UpdateFeatures(MgFeatureCommandCollection* commands);
 
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    /// \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
+    ///
+    /// \return
+    /// Returns a feature reader object that contains the set of properties 
+    /// inserted into the datastore by the insert command.
+    ///
+    /// \remarks
+    /// Transactions will be used internally if the provider supports them.
+    /// 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);
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    /// \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
+    ///
+    /// \return
+    /// Returns a feature reader object that contains the set of properties 
+    /// inserted into the datastore by the insert command.
+    ///
+    /// \remarks
+    /// Transactions will be used internally if the provider supports them.
+    /// 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);
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Updates all features that match the given filter with the specified property values
+    ///
+    /// \remarks
+    /// Transactions will be used internally if the provider supports them
+    ///
+    /// <!-- 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
+    ///
+    /// \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);
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    /// \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
+    ///
+    /// \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);
+
 INTERNAL_API:
 
     static MdfModel::LayerDefinition* GetLayerDefinition(MgResourceService* svcResource, MgResourceIdentifier* resId);

Modified: sandbox/jng/convenience_apis/Common/PlatformBase/Services/FeatureDefs.h
===================================================================
--- sandbox/jng/convenience_apis/Common/PlatformBase/Services/FeatureDefs.h	2014-06-25 15:30:06 UTC (rev 8263)
+++ sandbox/jng/convenience_apis/Common/PlatformBase/Services/FeatureDefs.h	2014-06-26 11:37:30 UTC (rev 8264)
@@ -77,6 +77,11 @@
     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;
 };
 /// \endcond
 

Modified: sandbox/jng/convenience_apis/Common/PlatformBase/Services/FeatureService.h
===================================================================
--- sandbox/jng/convenience_apis/Common/PlatformBase/Services/FeatureService.h	2014-06-25 15:30:06 UTC (rev 8263)
+++ sandbox/jng/convenience_apis/Common/PlatformBase/Services/FeatureService.h	2014-06-26 11:37:30 UTC (rev 8264)
@@ -982,6 +982,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: sandbox/jng/convenience_apis/Server/src/Services/Feature/FeatureOperationFactory.cpp
===================================================================
--- sandbox/jng/convenience_apis/Server/src/Services/Feature/FeatureOperationFactory.cpp	2014-06-25 15:30:06 UTC (rev 8263)
+++ sandbox/jng/convenience_apis/Server/src/Services/Feature/FeatureOperationFactory.cpp	2014-06-26 11:37:30 UTC (rev 8264)
@@ -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"
@@ -332,6 +336,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))
         {

Added: sandbox/jng/convenience_apis/Server/src/Services/Feature/OpDeleteFeatures.cpp
===================================================================
--- sandbox/jng/convenience_apis/Server/src/Services/Feature/OpDeleteFeatures.cpp	                        (rev 0)
+++ sandbox/jng/convenience_apis/Server/src/Services/Feature/OpDeleteFeatures.cpp	2014-06-26 11:37:30 UTC (rev 8264)
@@ -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()
+}

Added: sandbox/jng/convenience_apis/Server/src/Services/Feature/OpDeleteFeatures.h
===================================================================
--- sandbox/jng/convenience_apis/Server/src/Services/Feature/OpDeleteFeatures.h	                        (rev 0)
+++ sandbox/jng/convenience_apis/Server/src/Services/Feature/OpDeleteFeatures.h	2014-06-26 11:37:30 UTC (rev 8264)
@@ -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

Added: sandbox/jng/convenience_apis/Server/src/Services/Feature/OpInsertFeatures.cpp
===================================================================
--- sandbox/jng/convenience_apis/Server/src/Services/Feature/OpInsertFeatures.cpp	                        (rev 0)
+++ sandbox/jng/convenience_apis/Server/src/Services/Feature/OpInsertFeatures.cpp	2014-06-26 11:37:30 UTC (rev 8264)
@@ -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()
+}

Added: sandbox/jng/convenience_apis/Server/src/Services/Feature/OpInsertFeatures.h
===================================================================
--- sandbox/jng/convenience_apis/Server/src/Services/Feature/OpInsertFeatures.h	                        (rev 0)
+++ sandbox/jng/convenience_apis/Server/src/Services/Feature/OpInsertFeatures.h	2014-06-26 11:37:30 UTC (rev 8264)
@@ -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

Added: sandbox/jng/convenience_apis/Server/src/Services/Feature/OpInsertFeaturesBatched.cpp
===================================================================
--- sandbox/jng/convenience_apis/Server/src/Services/Feature/OpInsertFeaturesBatched.cpp	                        (rev 0)
+++ sandbox/jng/convenience_apis/Server/src/Services/Feature/OpInsertFeaturesBatched.cpp	2014-06-26 11:37:30 UTC (rev 8264)
@@ -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()
+}

Added: sandbox/jng/convenience_apis/Server/src/Services/Feature/OpInsertFeaturesBatched.h
===================================================================
--- sandbox/jng/convenience_apis/Server/src/Services/Feature/OpInsertFeaturesBatched.h	                        (rev 0)
+++ sandbox/jng/convenience_apis/Server/src/Services/Feature/OpInsertFeaturesBatched.h	2014-06-26 11:37:30 UTC (rev 8264)
@@ -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

Added: sandbox/jng/convenience_apis/Server/src/Services/Feature/OpUpdateMatchingFeatures.cpp
===================================================================
--- sandbox/jng/convenience_apis/Server/src/Services/Feature/OpUpdateMatchingFeatures.cpp	                        (rev 0)
+++ sandbox/jng/convenience_apis/Server/src/Services/Feature/OpUpdateMatchingFeatures.cpp	2014-06-26 11:37:30 UTC (rev 8264)
@@ -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()
+}

Added: sandbox/jng/convenience_apis/Server/src/Services/Feature/OpUpdateMatchingFeatures.h
===================================================================
--- sandbox/jng/convenience_apis/Server/src/Services/Feature/OpUpdateMatchingFeatures.h	                        (rev 0)
+++ sandbox/jng/convenience_apis/Server/src/Services/Feature/OpUpdateMatchingFeatures.h	2014-06-26 11:37:30 UTC (rev 8264)
@@ -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: sandbox/jng/convenience_apis/Server/src/Services/Feature/ServerFeatureService.cpp
===================================================================
--- sandbox/jng/convenience_apis/Server/src/Services/Feature/ServerFeatureService.cpp	2014-06-25 15:30:06 UTC (rev 8263)
+++ sandbox/jng/convenience_apis/Server/src/Services/Feature/ServerFeatureService.cpp	2014-06-26 11:37:30 UTC (rev 8264)
@@ -637,7 +637,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 (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,
+                                                        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: sandbox/jng/convenience_apis/Server/src/Services/Feature/ServerFeatureService.h
===================================================================
--- sandbox/jng/convenience_apis/Server/src/Services/Feature/ServerFeatureService.h	2014-06-25 15:30:06 UTC (rev 8263)
+++ sandbox/jng/convenience_apis/Server/src/Services/Feature/ServerFeatureService.h	2014-06-26 11:37:30 UTC (rev 8264)
@@ -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: sandbox/jng/convenience_apis/Server/src/Services/Feature/ServerFeatureService.vcxproj
===================================================================
--- sandbox/jng/convenience_apis/Server/src/Services/Feature/ServerFeatureService.vcxproj	2014-06-25 15:30:06 UTC (rev 8263)
+++ sandbox/jng/convenience_apis/Server/src/Services/Feature/ServerFeatureService.vcxproj	2014-06-26 11:37:30 UTC (rev 8264)
@@ -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>
@@ -799,6 +823,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 +846,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 +859,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" />

Modified: sandbox/jng/convenience_apis/Server/src/Services/Feature/ServerFeatureService.vcxproj.filters
===================================================================
--- sandbox/jng/convenience_apis/Server/src/Services/Feature/ServerFeatureService.vcxproj.filters	2014-06-25 15:30:06 UTC (rev 8263)
+++ sandbox/jng/convenience_apis/Server/src/Services/Feature/ServerFeatureService.vcxproj.filters	2014-06-26 11:37:30 UTC (rev 8264)
@@ -188,6 +188,18 @@
     <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>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="FeatureOperation.h">
@@ -385,6 +397,18 @@
     <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>
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="ServerFeatureService.rc" />

Modified: sandbox/jng/convenience_apis/Server/src/Services/Feature/ServerFeatureServiceBuild.cpp
===================================================================
--- sandbox/jng/convenience_apis/Server/src/Services/Feature/ServerFeatureServiceBuild.cpp	2014-06-25 15:30:06 UTC (rev 8263)
+++ sandbox/jng/convenience_apis/Server/src/Services/Feature/ServerFeatureServiceBuild.cpp	2014-06-26 11:37:30 UTC (rev 8264)
@@ -107,3 +107,7 @@
 #include "OpCommitTransaction.cpp"
 #include "OpRollbackTransaction.cpp"
 #include "OpUpdateFeaturesWithTransaction.cpp"
+#include "OpInsertFeatures.cpp"
+#include "OpInsertFeaturesBatched.cpp"
+#include "OpUpdateMatchingFeatures.cpp"
+#include "OpDeleteFeatures.cpp"

Modified: sandbox/jng/convenience_apis/Server/src/UnitTesting/TestFeatureService.cpp
===================================================================
--- sandbox/jng/convenience_apis/Server/src/UnitTesting/TestFeatureService.cpp	2014-06-25 15:30:06 UTC (rev 8263)
+++ sandbox/jng/convenience_apis/Server/src/UnitTesting/TestFeatureService.cpp	2014-06-26 11:37:30 UTC (rev 8264)
@@ -2978,4 +2978,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: sandbox/jng/convenience_apis/Server/src/UnitTesting/TestFeatureService.h
===================================================================
--- sandbox/jng/convenience_apis/Server/src/UnitTesting/TestFeatureService.h	2014-06-25 15:30:06 UTC (rev 8263)
+++ sandbox/jng/convenience_apis/Server/src/UnitTesting/TestFeatureService.h	2014-06-26 11:37:30 UTC (rev 8264)
@@ -41,6 +41,11 @@
     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);
@@ -89,6 +94,11 @@
     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 +120,9 @@
     void TestCase_JoinFdoFeatures();
     void TestCase_BenchmarkSqliteJoin();
     void TestCase_BenchmarkSqliteAggregateJoin();
+
+private:
+    STRING CreateTestDataStore(MgFeatureService* svcFeature, CREFSTRING provider, MgResourceIdentifier* fsId);
 };
 
 #endif // _TESTFEATURESERVICE_H

Modified: sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/MgTestRunner/Program.cs
===================================================================
--- sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/MgTestRunner/Program.cs	2014-06-25 15:30:06 UTC (rev 8263)
+++ sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/MgTestRunner/Program.cs	2014-06-26 11:37:30 UTC (rev 8264)
@@ -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: sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/TestCommon/CommonTests.cs
===================================================================
--- sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/TestCommon/CommonTests.cs	2014-06-25 15:30:06 UTC (rev 8263)
+++ sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/TestCommon/CommonTests.cs	2014-06-26 11:37:30 UTC (rev 8264)
@@ -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: sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/TestCommon/ExternalTests/CollectionTests.cs
===================================================================
--- sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/TestCommon/ExternalTests/CollectionTests.cs	2014-06-25 15:30:06 UTC (rev 8263)
+++ sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/TestCommon/ExternalTests/CollectionTests.cs	2014-06-26 11:37:30 UTC (rev 8264)
@@ -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);

Added: sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/TestCommon/ExternalTests/ConvenienceTests.cs
===================================================================
--- sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/TestCommon/ExternalTests/ConvenienceTests.cs	                        (rev 0)
+++ sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/TestCommon/ExternalTests/ConvenienceTests.cs	2014-06-26 11:37:30 UTC (rev 8264)
@@ -0,0 +1,470 @@
+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
+{
+    internal 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)
+        {
+            MgFeatureService featSvc = (MgFeatureService)factory.CreateService(MgServiceType.FeatureService);
+            var fsId = new MgResourceIdentifier("Library://UnitTests/Data/InsertFeatures.FeatureSource");
+            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);
+        }
+    }
+
+    public class FeatureServiceInsertFeaturesBatched : IExternalTest
+    {
+        public void Execute(IPlatformFactory factory, ITestLogger logger)
+        {
+            MgFeatureService featSvc = (MgFeatureService)factory.CreateService(MgServiceType.FeatureService);
+            var fsId = new MgResourceIdentifier("Library://UnitTests/Data/InsertFeaturesBatched.FeatureSource");
+            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);
+        }
+    }
+
+    public class FeatureServiceUpdateFeatures : IExternalTest
+    {
+        public void Execute(IPlatformFactory factory, ITestLogger logger)
+        {
+            MgFeatureService featSvc = (MgFeatureService)factory.CreateService(MgServiceType.FeatureService);
+
+            var fsId = new MgResourceIdentifier("Library://UnitTests/Data/UpdateFeatures.FeatureSource");
+            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);
+        }
+    }
+
+    public class FeatureServiceDeleteFeatures : IExternalTest
+    {
+        public void Execute(IPlatformFactory factory, ITestLogger logger)
+        {
+            MgFeatureService featSvc = (MgFeatureService)factory.CreateService(MgServiceType.FeatureService);
+
+            var fsId = new MgResourceIdentifier("Library://UnitTests/Data/DeleteFeatures.FeatureSource");
+            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++;
+            }
+            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);
+        }
+    }
+
+    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/UpdateFeatures.FeatureSource");
+            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);
+            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);
+        }
+    }
+
+    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/UpdateFeatures.FeatureSource");
+            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);
+            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);
+        }
+    }
+
+    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/UpdateFeatures.FeatureSource");
+            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);
+            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'");
+            Assert.AreEqual(1, updated);
+        }
+    }
+
+    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/UpdateFeatures.FeatureSource");
+            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);
+            int count = 0;
+            while (fr.ReadNext())
+            {
+                count++;
+            }
+            fr.Close();
+            Assert.AreEqual(5, count);
+
+            int deleted = layer.DeleteFeatures("Name = 'Test3'");
+            Assert.AreEqual(1, deleted);
+
+            var query = new MgFeatureQueryOptions();
+            fr = layer.SelectFeatures(query);
+            count = 0;
+            while (fr.ReadNext())
+            {
+                count++;
+            }
+            Assert.AreEqual(4, count);
+
+            query.SetFilter("Name = 'Test3'");
+            fr = layer.SelectFeatures(query);
+            count = 0;
+            while (fr.ReadNext())
+            {
+                count++;
+            }
+            fr.Close();
+            Assert.AreEqual(0, count);
+        }
+    }
+
+}

Modified: sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/TestCommon/ExternalTests/PropertiesTest.cs
===================================================================
--- sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/TestCommon/ExternalTests/PropertiesTest.cs	2014-06-25 15:30:06 UTC (rev 8263)
+++ sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/TestCommon/ExternalTests/PropertiesTest.cs	2014-06-26 11:37:30 UTC (rev 8264)
@@ -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);

Added: sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/TestCommon/Properties/Resources.Designer.cs
===================================================================
--- sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/TestCommon/Properties/Resources.Designer.cs	                        (rev 0)
+++ sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/TestCommon/Properties/Resources.Designer.cs	2014-06-26 11:37:30 UTC (rev 8264)
@@ -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);
+            }
+        }
+    }
+}

Added: sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/TestCommon/Properties/Resources.resx
===================================================================
--- sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/TestCommon/Properties/Resources.resx	                        (rev 0)
+++ sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/TestCommon/Properties/Resources.resx	2014-06-26 11:37:30 UTC (rev 8264)
@@ -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

Added: sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/TestCommon/Resources/TestLayer.txt
===================================================================
--- sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/TestCommon/Resources/TestLayer.txt	                        (rev 0)
+++ sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/TestCommon/Resources/TestLayer.txt	2014-06-26 11:37:30 UTC (rev 8264)
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LayerDefinition xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" version="1.0.0" xsi:noNamespaceSchemaLocation="LayerDefinition-1.0.0.xsd">
+  <VectorLayerDefinition>
+    <ResourceId>{0}</ResourceId>
+    <FeatureName>{1}</FeatureName>
+    <FeatureNameType>FeatureClass</FeatureNameType>
+    <Geometry>{2}</Geometry>
+    <VectorScaleRange>
+      <PointTypeStyle>
+        <DisplayAsText>false</DisplayAsText>
+        <AllowOverpost>false</AllowOverpost>
+        <PointRule>
+          <LegendLabel />
+          <PointSymbolization2D>
+            <Mark>
+              <Unit>Points</Unit>
+              <SizeContext>DeviceUnits</SizeContext>
+              <SizeX>10</SizeX>
+              <SizeY>10</SizeY>
+              <Rotation>0</Rotation>
+              <Shape>Square</Shape>
+              <Fill>
+                <FillPattern>Solid</FillPattern>
+                <ForegroundColor>ffffffff</ForegroundColor>
+                <BackgroundColor>ffffffff</BackgroundColor>
+              </Fill>
+              <Edge>
+                <LineStyle>Solid</LineStyle>
+                <Thickness>1</Thickness>
+                <Color>ff000000</Color>
+                <Unit>Points</Unit>
+              </Edge>
+            </Mark>
+          </PointSymbolization2D>
+        </PointRule>
+      </PointTypeStyle>
+      <LineTypeStyle>
+        <LineRule>
+          <LegendLabel />
+          <LineSymbolization2D>
+            <LineStyle>Solid</LineStyle>
+            <Thickness>1</Thickness>
+            <Color>ff000000</Color>
+            <Unit>Points</Unit>
+          </LineSymbolization2D>
+        </LineRule>
+      </LineTypeStyle>
+      <AreaTypeStyle>
+        <AreaRule>
+          <LegendLabel />
+          <AreaSymbolization2D>
+            <Fill>
+              <FillPattern>Solid</FillPattern>
+              <ForegroundColor>ffffffff</ForegroundColor>
+              <BackgroundColor>ffffffff</BackgroundColor>
+            </Fill>
+            <Stroke>
+              <LineStyle>Solid</LineStyle>
+              <Thickness>1</Thickness>
+              <Color>ff000000</Color>
+              <Unit>Points</Unit>
+            </Stroke>
+          </AreaSymbolization2D>
+        </AreaRule>
+      </AreaTypeStyle>
+    </VectorScaleRange>
+  </VectorLayerDefinition>
+</LayerDefinition>
\ No newline at end of file

Added: sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/TestCommon/Resources/TestMapDef.txt
===================================================================
--- sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/TestCommon/Resources/TestMapDef.txt	                        (rev 0)
+++ sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/TestCommon/Resources/TestMapDef.txt	2014-06-26 11:37:30 UTC (rev 8264)
@@ -0,0 +1,12 @@
+<?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>
\ No newline at end of file

Modified: sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/TestCommon/TestCommon.csproj
===================================================================
--- sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/TestCommon/TestCommon.csproj	2014-06-25 15:30:06 UTC (rev 8263)
+++ sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/TestCommon/TestCommon.csproj	2014-06-26 11:37:30 UTC (rev 8264)
@@ -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: sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/TestMapGuideApi/ExternalTests/CollectionTests.cs
===================================================================
--- sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/TestMapGuideApi/ExternalTests/CollectionTests.cs	2014-06-25 15:30:06 UTC (rev 8263)
+++ sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/TestMapGuideApi/ExternalTests/CollectionTests.cs	2014-06-26 11:37:30 UTC (rev 8264)
@@ -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");



More information about the mapguide-commits mailing list