I have created FileWorkspaceUtils that inherits from WorkspaceUtils, it adds the functions GetRows and GetFeatures that return the raw IRow and IFeature data. In WorkspaceUtils I preferred that the low level programmer won’t even know he has something called IRow or IFeature.
- public class FileWorkspaceUtils:WorkspaceUtils
- {
- public FileWorkspaceUtils(IFeatureWorkspace workspace) : base(workspace)
- {
- }
- public List<IRow> GetRows(string tableName)
- {
- var result = new List<IRow>();
- DoActionOnSelectRows(tableName, null, row => result.Add(row.Clone()));
- return result;
- }
- public List<IFeature> GetFeatures(string layerName)
- {
- var result = new List<IFeature>();
- DoActionOnSelectFeatures(layerName, null, feature => result.Add(feature.Clone()));
- return result;
- }
- }
//TODO: Post on the wonder of Extension Methods (row.Clone())
I have added code to WorkspaceProvider so that it will return the FileWorkspaceUtils (independent of File/Personal GeoDatabase):
- private const string PersonalGeoDatabaseFileExtension = ".MDB";
- private const string FileGeoDatabaseFileExtension = ".GDB";
- /// <summary>
- /// Get a File WorkspaceUtils for Personal and File GeoDatabase
- /// </summary>
- /// <param name="filePath"></param>
- /// <returns></returns>
- public FileWorkspaceUtils GetFileWorkspace(string filePath)
- {
- var extension = (Path.GetExtension(filePath) ?? String.Empty).ToUpper();
- if (extension.CompareTo(PersonalGeoDatabaseFileExtension) == 0)
- return CreatePersonalGeoDatabaseWorkspace(filePath);
- if (extension.CompareTo(FileGeoDatabaseFileExtension) == 0)
- return CreateFileGeoDatabaseWorkspace(filePath);
- throw new NotImplementedException("The only supported file types are mdb and gdb. Not: " + extension);
- }
- private FileWorkspaceUtils CreatePersonalGeoDatabaseWorkspace(string filePath)
- {
- AccessWorkspaceFactory workspaceFactory = new AccessWorkspaceFactoryClass();
- var workspace = workspaceFactory.OpenFromFile(filePath, 0);
- return new FileWorkspaceUtils((IFeatureWorkspace)workspace);
- }
- private FileWorkspaceUtils CreateFileGeoDatabaseWorkspace(string filePath)
- {
- FileGDBWorkspaceFactory workspaceFactory = new FileGDBWorkspaceFactoryClass();
- var workspace = workspaceFactory.OpenFromFile(filePath, 0);
- return new FileWorkspaceUtils((IFeatureWorkspace)workspace);
- }
The only problem is it doesn’t work, my unit tests that just check GetFileWorkspace throws a COMException:
Test method CompanyName.GIS.Core.Esri.Tests.WorkspaceProviderTests.GetWorkspace_ValidPersonalGeoDB_GetFileWorkspaceUtils threw exception:
System.Runtime.InteropServices.COMException: Exception from HRESULT: 0x80040228
at ESRI.ArcGIS.DataSourcesGDB.AccessWorkspaceFactoryClass.OpenFromFile(String fileName, Int32 hWnd)
at Core.Esri.WorkspaceProvider.CreatePersonalGeoDatabaseWorkspace(String filePath) in WorkspaceProvider.cs: line 200
at Core.Esri.WorkspaceProvider.GetFileWorkspace(String filePath) in WorkspaceProvider.cs: line 189
at Core.Esri.Tests.WorkspaceProviderTests.GetWorkspace_ValidPersonalGeoDB_GetFileWorkspaceUtils() in WorkspaceProviderTests.cs: line 55
The problem was caused by Licensing, I changed EsriInitilization to contained the old style licensing as well (the one with IAoInitialize, the new stuff is using RuntimeManager):
All my unit tests (427 tests) pass, so it works…
- public class EsriInitilization
- {
- private static bool _isStarted = false;
- public static void Start()
- {
- if (_isStarted)
- return;
- if (!Initialize(ProductCode.Server, esriLicenseProductCode.esriLicenseProductCodeArcServer))
- {
- if(!Initialize(ProductCode.Engine, esriLicenseProductCode.esriLicenseProductCodeEngineGeoDB))
- {
- throw new ApplicationException(
- "Unable to bind to ArcGIS license Server nor to Engine. Please check your licenses.");
- }
- }
- _isStarted = true;
- }
- private static bool Initialize(ProductCode product, esriLicenseProductCode esriLicenseProduct)
- {
- if (RuntimeManager.Bind(product))
- {
- IAoInitialize aoInit = new AoInitializeClass();
- aoInit.Initialize(esriLicenseProduct);
- return true;
- }
- return false;
- }
- }
That still throw an exception, this time simply because IFeature refused to be cloned – though it implemented ESRI’s IClone interface. The error I got was:
//TODO: Write error and new code
//TODO: Post after writing about Extension Method (TODO above)
Resources:
Esri Forum: COM Exception 0x80040228 When Opening a Personal Geodatabase
Keywords: License, COM, exception, IWorkspace, engine, Server, ArcGis, ESRI, Unit tests, MDB, GDB