IFeatureWorkspace.CreateFeatureClass on ArcServer

Subject IFeatureWorkspace.CreateFeatureClass on ArcServer 
Author Greg Walker 
Date Dec 14, 2005 
Message I have an ASP.NET 1.1 web application with several SDE layers on it. I have recently been asked if it is possible for users to click a button and download those layers as shapefiles. I've been jumping through hoops trying to get this to work, using every example I come across and learning a lot along the way.

Eventually, the method that made the most sense to me (code shown below) was to create a new featureclass with the same fields as the SDE layer, then open cursors to iterate through all of the features in the SDE layer and copy them into the new featureclass. However, the application dies with a COM exception (0x80004005) when it reaches the CreateFeatureClass() call. A little extra debugging in Visual Studio revealed another COM exception (0x80070005 - access denied) immediately before the other one was returned.

Before I give up all hope of dynamically exporting these layers (necessary because of the frequency with which they change), I have one question: Can the IFeatureWorkspace.CreateFeatureClass() method be used in an ArcServer ASP.NET web application?

Thanks is advance, 
 
C#
            string m_host         = Convert.ToString(Session["map_host"]);
            string m_serverobject = Convert.ToString(Session["map_serverobject"]);
            string m_dataframe    = Convert.ToString(Session["map_dataframe"]);
            string m_contextname  = String.Format("svrctx_{0}_{1}", m_host, m_serverobject);
            IServerContext m_ctx = null;
            WebMap webMap = null;
            object o = Session[m_contextname];
            if (o!=null)
            {
            // ServerContext saved in session for non-pooled serverobject.
            // Create WebMap with it.
            m_ctx = o as IServerContext;
            webMap = new WebMap(m_ctx, m_host, m_dataframe);
            }
            else
            {
            // No ServerContext in session, so this is a pooled serverobject.
            // Create WebMap and set necessary parameters to execute identify
            webMap = new WebMap(new ESRI.ArcGIS.Server.WebControls.ServerConnection(m_host,true),m_serverobject,m_dataframe);
            m_ctx = webMap.ServerContext;
            webMap.ManageLifetime(m_ctx);
            }
            IFeatureLayer pFLayer = (IFeatureLayer)((IMapServerObjects)webMap.MapServer).get_Layer(m_dataframe, 7);
            IFeatureCursor inputCursor = pFLayer.FeatureClass.Search(null, false);
            IWorkspaceFactory wsFactory     = new ShapefileWorkspaceFactoryClass();
            IFeatureWorkspace featWorkspace = (IFeatureWorkspace)wsFactory.OpenFromFile(@"c:\temp\esri\", 0);
            IFields fields = pFLayer.FeatureClass.Fields;
            IFeatureClass outputFeatClass = featWorkspace.CreateFeatureClass(pFLayer.Name, fields, pFLayer.FeatureClass.CLSID, null, pFLayer.FeatureClass.FeatureType, pFLayer.DataSourceType, "");
            IFeatureCursor outputFeatCursor = outputFeatClass.Insert(true);
            IFields outputFields = outputFeatClass.Fields;
            IFeatureBuffer featBuff = null;
            IFeature feature = inputCursor.NextFeature();
            while(feature != null)
            {
            featBuff = outputFeatClass.CreateFeatureBuffer();
            for(int i = 0; i < fields.FieldCount; i++)
            if(fields.get_Field(i).Type != ESRI.ArcGIS.Geodatabase.esriFieldType.esriFieldTypeOID && fields.get_Field(i).Type != ESRI.ArcGIS.Geodatabase.esriFieldType.esriFieldTypeBlob)
            if(outputFields.FindField(fields.get_Field(i).Name) != -1)
            featBuff.set_Value(outputFields.FindField(fields.get_Field(i).Name), feature.get_Value(i));
            outputFeatCursor.InsertFeature(featBuff);
            feature = inputCursor.NextFeature();
            }
            outputFeatCursor.Flush();
 
   
• Top Print Reply Alert Moderator   
Subject Re: IFeatureWorkspace.CreateFeatureClass on ArcServer 
Author Greg Walker 
Date Dec 14, 2005 
Message Some additional information I just remembered. I'm developing this webapp on a Windows XP machine with ArcGIS 9.1 Desktop installed (using the 9.0 ADF). When I deploy the webapp to our production server (Windows 2003, no ArcGIS Desktop, using 9.0 ADF), I get an error that the COM object with CLSID {CLSID here} is not found or is not registered.

This is one of the things that makes me wonder if this is possible. 
   
• Top Print Reply Alert Moderator   
Subject Re: IFeatureWorkspace.CreateFeatureClass on ArcServer 
Author Brent Hoskisson 
Date Dec 15, 2005 
Message I've said this in several other threads. I still claim it's true: 99% of the time (if you are not dealing directly with display issues) -- If you can do it in generic arc objects, you can do it ArcGIS server.

Just switch all the "new"s to "CreateObjects".

Here is code that works for me for downloading layers. This downloads to a place on the ArcGIS Server server box. It is then up to you to place the files somewhere where they can be downloaded by the user.

Good Luck
Brent 
 
//this code is part of a larger class where the server context and
            //web object are initialized in the class constructor.
            //This code works for adding layers as shapefiles, PGDB's and SDE GDB's.
            //With VERY little tweaking it also works for copying standalone tables.
            public string ConvertFeatureClass
            (IFeatureClass pFC, IWorkspace poutWS, string outFeatureClassName)
            {
            //Get input FeatureClassName and Workspace...
            IDataset pinDS = (IDataset) pFC;
            IFeatureClassName pinFCName = (IFeatureClassName) pinDS.FullName;
            IWorkspace pinWS = pinDS.Workspace;
            //Set output WorkspaceName...
            IDataset poutDS = (IDataset) poutWS;
            IWorkspaceName poutWSName =  (IWorkspaceName) poutDS.FullName;
            //Set output FeatureClassName...
            IFeatureClassName poutFCName = sc.CreateObject("esriGeodatabase.FeatureClassName") as IFeatureClassName;
            wo.ManageLifetime(poutFCName);
            IDatasetName pDSName = (IDatasetName) poutFCName;
            pDSName.Name = outFeatureClassName;
            pDSName.WorkspaceName = poutWSName;
            //Get fields for input feature class and run them through field checker...
            IFieldChecker pFldChecker = sc.CreateObject("esriGeodatabase.FieldChecker") as IFieldChecker;
            wo.ManageLifetime(pFldChecker);
            IFields pFlds = pFC.Fields;
            pFldChecker.InputWorkspace = pinWS;
            pFldChecker.ValidateWorkspace = poutWS;
            IFields poutFlds = null;
            IEnumFieldError pEnumFldError = null;
            pFldChecker.Validate(pFlds, out pEnumFldError, out poutFlds);
            //Convert the data...
            IFeatureDataConverter pFDC = sc.CreateObject("esriGeodatabase.FeatureDataConverter") as IFeatureDataConverter;
            wo.ManageLifetime(pFDC);
            try
            {
            pFDC.ConvertFeatureClass(pinFCName, null, null, poutFCName,
            null, poutFlds, "", 1000, 0);
            }
            catch (Exception ex)
            {
            return ex.Message;
            }
            return "success";
            }
            
 
   
• Top Print Reply Alert Moderator   
Subject Re: IFeatureWorkspace.CreateFeatureClass on ArcServer 
Author Greg Walker 
Date Dec 15, 2005 
Message Excellent, thanks very much. I hadn't realized that the output files were going to be stored on the ArcGIS Server machine - I expected them on the web server. Apparently the "access denied" exception arose from the fact that the output directory I specified didn't exist on the ArcGIS Server box.

I pasted in your code and modified it to use my server context and webmap objects. It seems to work great until it gets to the ConvertFeatureClass call. I end up with dbf, shp, and shx files on disk but they're empty. The exception raised on the ConvertFeatureClass call is:

Error: System.Runtime.InteropServices.COMException (0x80040205): Create output feature class failed

I posted the code as I have it now below. Do you have any suggestions or notice any dumb mistakes I've made? Thanks a ton for your help so far. I've done very little ArcGIS development and I'm learning a lot through this one particular project. Hopefully I won't have stupid problems like this in the future. :) 
 
string m_host         = Convert.ToString(Session["map_host"]);
            string m_serverobject = Convert.ToString(Session["map_serverobject"]);
            string m_dataframe    = Convert.ToString(Session["map_dataframe"]);
            string m_contextname  = String.Format("svrctx_{0}_{1}", m_host, m_serverobject);
            IServerContext m_ctx = null;
            WebMap webMap = null;
            object o = Session[m_contextname];
            if (o!=null)
            {
            // ServerContext saved in session for non-pooled serverobject.
            // Create WebMap with it.
            m_ctx = o as IServerContext;
            webMap = new WebMap(m_ctx, m_host, m_dataframe);
            }
            else
            {
            // No ServerContext in session, so this is a pooled serverobject.
            // Create WebMap and set necessary parameters to execute identify
            webMap = new WebMap(new ESRI.ArcGIS.Server.WebControls.ServerConnection(m_host,true),
            m_serverobject,m_dataframe);
            m_ctx = webMap.ServerContext;
            webMap.ManageLifetime(m_ctx);
            }
            IFeatureLayer pFLayer = (IFeatureLayer)((IMapServerObjects)webMap.MapServer).get_Layer(m_dataframe,
            layerID);
            webMap.ManageLifetime(pFLayer);
            IFeatureClass pFC = pFLayer.FeatureClass;
            IWorkspaceFactory wsf = m_ctx.CreateObject("esriDataSourcesFile.ShapefileWorkspaceFactory")
            as IWorkspaceFactory;
            IWorkspace poutWS = wsf.OpenFromFile(@"c:\temp\esri", 0);
            webMap.ManageLifetime(wsf);
            webMap.ManageLifetime(poutWS);
            string outFeatureClassName = pFLayer.Name;
            //Get input FeatureClassName and Workspace...
            IDataset pinDS = (IDataset) pFC;
            IFeatureClassName pinFCName = (IFeatureClassName) pinDS.FullName;
            IWorkspace pinWS = pinDS.Workspace;
            //Set output WorkspaceName...
            IDataset poutDS = (IDataset) poutWS;
            IWorkspaceName poutWSName =  (IWorkspaceName) poutDS.FullName;
            //Set output FeatureClassName...
            IFeatureClassName poutFCName = m_ctx.CreateObject("esriGeodatabase.FeatureClassName")
            as IFeatureClassName;
            webMap.ManageLifetime(poutFCName);
            IDatasetName pDSName = (IDatasetName) poutFCName;
            pDSName.Name = outFeatureClassName;
            pDSName.WorkspaceName = poutWSName;
            //Get fields for input feature class and run them through field checker...
            IFieldChecker pFldChecker = m_ctx.CreateObject("esriGeodatabase.FieldChecker") as IFieldChecker;
            webMap.ManageLifetime(pFldChecker);
            IFields pFlds = pFC.Fields;
            pFldChecker.InputWorkspace = pinWS;
            pFldChecker.ValidateWorkspace = poutWS;
            IFields poutFlds = null;
            IEnumFieldError pEnumFldError = null;
            pFldChecker.Validate(pFlds, out pEnumFldError, out poutFlds);
            //Convert the data...
            IFeatureDataConverter pFDC = m_ctx.CreateObject("esriGeodatabase.FeatureDataConverter")
            as IFeatureDataConverter;
            webMap.ManageLifetime(pFDC);
            // try/catch block removed - this entire function is already wrapped in one
            // *** EXCEPTION HERE ***
            pFDC.ConvertFeatureClass(pinFCName, null, null, poutFCName, null, poutFlds, "", 1000, 0);
            // *** EXCEPTION HERE ***
 
   
• Top Print Reply Alert Moderator   
Subject Re: IFeatureWorkspace.CreateFeatureClass on ArcServer 
Author Brent Hoskisson 
Date Dec 15, 2005 
Message Make sure that your ArcContainer account has permissions to write to the directory you are creating the shapefile in. I think it may need full permissions. I just write to the output directory that all the Server apps write to. The ASPNET user probably needs permissions as well.

Good Luck
Brent 
   
• Top Print Reply Alert Moderator   
Subject Re: IFeatureWorkspace.CreateFeatureClass on ArcServer 
Author Greg Walker 
Date Dec 15, 2005 
Message Thanks for the reply. I had not set the permissions on that directory, but doing so didn't help. It is creating the files, but it isn't putting anything in them - they open in ArcMap, but have no features.

One thing I wonder is whether a version difference could cause this kind of problem. I've got the 9.0 ADF on my machine but our server is 9.1. I would try it with the 9.1 ADF, but nothing I can do will make it install. It consistently tells me that I still have 9.0 products installed after I have uninstalled the 9.0 ADF. Maybe it's a dirty uninstall. But that's a whole other thread.

Thanks again for all your help, and Merry Christmas to you. 
   
• Top Print Reply Alert Moderator   
Subject Re: IFeatureWorkspace.CreateFeatureClass on ArcServer 
Author Brent Hoskisson 
Date Jan 19, 2006 
Message Did you fix this? I think I may have duplicated your problem. Is the download code on the same web page as your map? When the download button is on the same web form as my map, It works. When I try to put the button on a different page, the tables are set up correctly, but no data actually gets transferred.

I have also duplicated this in generic ArcObjects. If the downloading is done on the same thread as the map it works, if the downloading is done on another thread (allowing the user to work with the map while stuff is downloading) nothing gets downloaded.

I don't know whether this is a feature or a bug.

Good Luck
Brent 
   
• Top Print Reply Alert Moderator   
Subject Re: IFeatureWorkspace.CreateFeatureClass on ArcServer 
Author K G 
Date Jun 20, 2006 
Message Wow. Thank you Brent. Very helpful code. I got this up and running quickly as a web service that writes out to the temp directory on the ags server.
Now I'm wondering if I can get a subset of the entire dataset to be exported? I know that second parameter is for an IQueryFilter but in the example on EDN they use it to restrict the fields going out not the features. Any tips on how I might subset the features going out?
And thanks again.

I think I agree with your 99% assessment however sometimes it seems like sometimes it takes 99 tries to get the code correct! 
  K G
Wannabe GIS Superstar 
   
• Top Print Reply Alert Moderator   
Subject Re: IFeatureWorkspace.CreateFeatureClass on ArcServer 
Author K G 
Date Sep 08, 2006 
Message Has anyone ever gotten AGS to create a new empty shapefile using the CreateFeatureClass method?

It keeps bailing on that line like the original question in this thread states. 
  K G
Wannabe GIS Superstar 
   
• Top Print Reply Alert Moderator   
Subject Re: IFeatureWorkspace.CreateFeatureClass on ArcServer 
Author K G 
Date Dec 27, 2006 
Message Still struggling with this one. I'm seeing the same error as you folks are. I changed course and tried to go with the ConvertFeatureClass method at:

http://edndoc.esri.com/arcobjects/9.2/ComponentHelp/esriGeoDatabase/IFeatureDataConverter_ConvertFeatureClass_Example.htm

This is not working either but I think that it should but the code seems to me to be bad. If you take a close look you will see that the actual work happens here:

IEnumInvalidObject enumErrors = fctofc.ConvertFeatureClass(sourceFeatureClassName, queryFilter, null, targetFeatureClassName, geometryDef, targetFeatureClassFields, "", 1000, 0);

However, the source and target FeatureClassName variables are effectively null at this point because they are never set within the sample code, as far as I can tell. Can someone else have a look at this and tell me if I'm insane?
 
 
public void IFeatureDataConverter_ConvertFeatureClass(IWorkspace sourceWorkspace, IWorkspace targetWorkspace, string nameOfSourceFeatureClass, string nameOfTargetFeatureClass)
            {
            //create source workspace name
            IDataset sourceWorkspaceDataset = (IDataset)sourceWorkspace;
            IWorkspaceName sourceWorkspaceName = (IWorkspaceName)sourceWorkspaceDataset.FullName;
            //create source dataset name
            IFeatureClassName sourceFeatureClassName = new FeatureClassNameClass();
            IDatasetName sourceDatasetName = (IDatasetName)sourceFeatureClassName;
            sourceDatasetName.WorkspaceName = sourceWorkspaceName;
            sourceDatasetName.Name = nameOfSourceFeatureClass;
            //create target workspace name
            IDataset targetWorkspaceDataset = (IDataset)targetWorkspace;
            IWorkspaceName targetWorkspaceName = (IWorkspaceName)targetWorkspaceDataset.FullName;
            //create target dataset name
            IFeatureClassName targetFeatureClassName = new FeatureClassNameClass();
            IDatasetName targetDatasetName = (IDatasetName)targetFeatureClassName;
            targetDatasetName.WorkspaceName = targetWorkspaceName;
            targetDatasetName.Name = nameOfTargetFeatureClass;
            //Open input Featureclass to get field definitions.
            ESRI.ArcGIS.esriSystem.IName sourceName = (ESRI.ArcGIS.esriSystem.IName)sourceFeatureClassName;
            IFeatureClass sourceFeatureClass = (IFeatureClass)sourceName.Open();
            //Validate the field names because you are converting between different workspace types.
            IFieldChecker fieldChecker = new FieldCheckerClass();
            IFields targetFeatureClassFields;
            IFields sourceFeatureClassFields = sourceFeatureClass.Fields;
            IEnumFieldError enumFieldError;
            // Most importantly set the input and validate workspaces!
            fieldChecker.InputWorkspace = sourceWorkspace;
            fieldChecker.ValidateWorkspace = targetWorkspace;
            fieldChecker.Validate(sourceFeatureClassFields, out enumFieldError, out targetFeatureClassFields);
            // Loop through the output fields to find the geomerty field
            IField geometryField;
            for (int i = 0; i < targetFeatureClassFields.FieldCount; i++)
            {
            if (targetFeatureClassFields.get_Field(i).Type == esriFieldType.esriFieldTypeGeometry)
            {
            geometryField = targetFeatureClassFields.get_Field(i);
            // Get the geometry field's geometry defenition
            IGeometryDef geometryDef = geometryField.GeometryDef;
            //Give the geometry definition a spatial index grid count and grid size
            IGeometryDefEdit targetFCGeoDefEdit = (IGeometryDefEdit)geometryDef;
            targetFCGeoDefEdit.GridCount_2 = 1;
            targetFCGeoDefEdit.set_GridSize(0, 0); //Allow ArcGIS to determine a valid grid size for the data loaded
            targetFCGeoDefEdit.SpatialReference_2 = geometryField.GeometryDef.SpatialReference;
            // we want to convert all of the features
            IQueryFilter queryFilter = new QueryFilterClass();
            queryFilter.WhereClause = "";
            // Load the feature class
            IFeatureDataConverter fctofc = new FeatureDataConverterClass();
            IEnumInvalidObject enumErrors = fctofc.ConvertFeatureClass(sourceFeatureClassName, queryFilter, null, targetFeatureClassName, geometryDef, targetFeatureClassFields, "", 1000, 0);
            break;
            }
            }
            }
 
  K G
Wannabe GIS Superstar 
   
• Top Print Reply Alert Moderator   
Subject Re: IFeatureWorkspace.CreateFeatureClass on ArcServer 
Author K G 
Date Dec 27, 2006 
Message Maybe I am not creating the server objects in the proper context but I don't know which ones need to be CreateObject and which don't? 
  K G
Wannabe GIS Superstar 
   
• Top Print Reply Alert Moderator   
Subject Re: IFeatureWorkspace.CreateFeatureClass on ArcServer 
Author Andrew Haigh 
Date Dec 28, 2006 
Message KG

My take on your problem would be that your not correctly creating the COM objects...

Looking at the sample page, it looks like it's written to run in ArcCatlog... have you tested the example in ArcCatalog by passing in valid paramaeters?

To run the code on ArcGIS Server you will need make changes to how you create the COM Objects:

1. If the code above is included in a custom SOC object, then it looks like it should work.

2. If the code is just run as part of an ASPX page then you will need to replace every instance of 'new' with SERVERCONTEXT.CreateObject("")

Hope this helps.

Andrew 
   
• Top Print Reply Alert Moderator   
Subject Re: IFeatureWorkspace.CreateFeatureClass on ArcServer 
Author Greg Walker 
Date Jan 03, 2007 
Message All,

I haven't added anything to this discussion since my initial series of posts. I also haven't gone back to this problem. I wound up using ArcMap to export the SDE layers into shapefiles and then created a link directly to those, rather than trying to dynamically create the shapefiles on the server. The project I was working on was too time-constrained for much research into the problem, so we had to find another solution.

Unfortunately, I've never revisited the issue. I still have all of that old code in comments, but it never worked - my last post was the most progress I made. Sorry I couldn't be more help, and best of luck to all of you still working on it! 
   
posted @ 2007-11-14 09:44  四两  阅读(2420)  评论(0编辑  收藏  举报
加油,哥们,现在开始!