In ArcGIS PRO 2.01, layer.GetFieldDescriptions() does not work after adding fields with Geoprocessing.ExecuteToolAsync

378
1
11-06-2017 01:16 PM
HoriaTudosie
Occasional Contributor II

At least this is how it looks to me: I have upgraded recently from 1.x to 2.01 and the code breaks:

    private async Task<bool> ExecuteAddFieldTool(FeatureLayer layer, KeyValuePair<string, string> field,
        string fieldType, int? fieldLength = null, bool isNullable = true)
    {
        PushBusy(field.Value);

        try
        {
            if (Model.HasField(layer, field)) return true;

            return await QueuedTask.Run(() =>
            {
                try
                {
                    var cts = new CancellationTokenSource();
                    Geoprocessing.ExecuteToolAsync(
                        "management.AddField",
                        values: Geoprocessing.MakeValueArray(
                            layer.Name, field.Key, fieldType.ToUpper(),
                            null, null,
                            fieldLength, field.Value, 
                            isNullable ? "NULABLE" : "NON_NULLABLE"),
                        environments:
                            Geoprocessing.MakeEnvironmentArray(
                                workspace: ((IInternalMapMember)layer).WorkspaceName),
                        cancelToken: cts.Token,
                        callback: (eventName, o) =>
                        {
                            switch (eventName)
                            {
                                case "OnValidate":
                                    if (((IGPMessage[])o).Any(it => it.Type == GPMessageType.Warning))
                                    {
                                        var fieldExists = ((IGPMessage[])o).FirstOrDefault(it => it.ErrorCode == 12);
                                        if (fieldExists != null)
                                        {
                                            cts.Cancel();
                                        }
                                        else
                                        {
                                            Debug.WriteLine($"AddField '{eventName}': {o}");
                                        }
                                    }
                                    break;
                                case "OnProgressPos":
                                    Debug.WriteLine($"AddField '{eventName}': {o} %");
                                    break;
                                case "OnMessage":
                                case "OnProgressMessage":
                                default:
                                    Debug.WriteLine($"AddField '{eventName}': {o}");
                                    break;
                            }

                        });
                    var fields = layer.GetFieldDescriptions();
                    Debug.WriteLine("Fields Count: " + fields.Count);

                    return true;
                }
                catch (Exception ex)
                {
                    MessageBox.Show($@"{ex.Message}{Environment.NewLine}{Environment.NewLine}{ex.StackTrace}",
                        $"ExecuteAddFieldTool - {ex.GetType().Name}",
                        MessageBoxButton.OK, MessageBoxImage.Error);
                    return false;
                }
            });
        }
        finally
        {
            PopBusy();
        }
    }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

In line 56 I'm checking the number of fields: the added field is not part of the field definitions.

Indeed, later on, the field is missing from this list.

When exiting and saving saving the project, the field appears on the next run.

(However, I cannot do that problematically since the code executes on a very complex thread and Project.Current.SaveAsync() wants to execute only on the UI thread!)

I'm pretty sure that in the previous version of Pro this did not happen! (But I cannot check again...)

This is the output of the Output window for running in between lines 3 and 72:

PushBusy 'Paired Feature'
AddField 'OnBeginExecute': 1839808
STOPHERE
AddField 'OnMessage': <msg code='0' type='2'>Start Time: Monday, November 06, 2017 4:12:21 PM</msg>
AddField 'OnProgressPos': 1 %
AddField 'OnProgressPos': 2 %
AddField 'OnProgressPos': 3 %
AddField 'OnProgressPos': 4 %
AddField 'OnProgressPos': 5 %
AddField 'OnProgressPos': 6 %
AddField 'OnProgressPos': 7 %
AddField 'OnProgressPos': 8 %
AddField 'OnProgressPos': 9 %
AddField 'OnProgressPos': 10 %
AddField 'OnProgressPos': 11 %
AddField 'OnMessage': <msg code='0' type='0'>Adding db_pairedId to RoadSegment_MUN...</msg>
AddField 'OnProgressPos': 12 %
AddField 'OnMessage': <msg code='0' type='3'>Succeeded at Monday, November 06, 2017 4:12:21 PM (Elapsed Time: 0.33 seconds)</msg>
AddField 'OnProgressPos': -1 %
STOPHERE
AddField 'OnProgressMessage': Updating...
AddField 'OnProgressMessage': Updating...
AddField 'OnEndExecute': ArcGIS.Desktop.GeoProcessing.gpResultImpl
Fields Count: 89
PopBusy 'Paired Feature'

Line 24 - I was expecting 90!

(B.T.W. - what is STOPHERE in lines 3 and 20? Is not part of my code!)

0 Kudos
1 Reply
HoriaTudosie
Occasional Contributor II

Another attempt to debug the issue:

        private async Task<bool> ExecuteAddFieldTool(FeatureLayer layer, KeyValuePair<string, string> field,
            string fieldType, int? fieldLength = null, bool isNullable = true)
        {
            PushBusy(field.Value);

            try
            {
                if (Model.HasField(layer, field)) return true;

                var results = await QueuedTask.Run(() =>
                {
                    try
                    {
                        var cts = new CancellationTokenSource();
                        Geoprocessing.ExecuteToolAsync(
                            "management.AddField",
                            values: Geoprocessing.MakeValueArray(
                                layer.Name, field.Key, fieldType.ToUpper(),
                                null, null,
                                fieldLength, field.Value,
                                isNullable ? "NULABLE" : "NON_NULLABLE"),
                            environments:
                                Geoprocessing.MakeEnvironmentArray(
                                    workspace: ((IInternalMapMember)layer).WorkspaceName),
                            cancelToken: cts.Token,
                            callback: (eventName, o) =>
                            {
                                switch (eventName)
                                {
                                    case "OnValidate":
                                        if (((IGPMessage[])o).Any(it => it.Type == GPMessageType.Warning))
                                        {
                                            var fieldExists = ((IGPMessage[])o).FirstOrDefault(it => it.ErrorCode == 12);
                                            if (fieldExists != null)
                                            {
                                                cts.Cancel();
                                            }
                                            //else
                                            //{
                                            //    Debug.WriteLine($"AddField '{eventName}': {o}");
                                            //}
                                        }
                                        break;
                                    case "OnEndExecute":
                                        if (FieldDefinitions != null && FieldDefinitions.All(f => f[0] != field.Key))
                                        {
                                            FieldDefinitions.Add(new[] { field.Key, field.Value });
                                            Debug.WriteLine($"OnEndExecute");
                                        }
                                        break;
                                        //case "OnProgressPos":
                                        //case "OnMessage":
                                        //case "OnProgressMessage":
                                        //default:
                                        //    Debug.WriteLine($"AddField '{eventName}': {o}");
                                        //    break;
                                }

                            });
                        //var fields = await QueuedTask.Run(() => layer.GetFieldDescriptions());
                        //Debug.WriteLine("Fields Count: " + fields.Count);

                        return true;
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show($@"{ex.Message}{Environment.NewLine}{Environment.NewLine}{ex.StackTrace}",
                            $"ExecuteAddFieldTool - {ex.GetType().Name}",
                            MessageBoxButton.OK, MessageBoxImage.Error);
                        return false;
                    }
                });
                var fields = await QueuedTask.Run(() => layer.GetFieldDescriptions());
                Debug.WriteLine($"GetFieldDescriptions Count: {fields.Count} instead of: {FieldDefinitions.Count}");

                return results;
            }
            finally
            {
                PopBusy();
                Debug.WriteLine("finally");
            }
        }
‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

I have put a break-point on line 3. When this is hit, I clear the output window of VS 2015.

Another break-point in line 82. When that was hit, I'm getting the following text in the Output window:

PushBusy 'Paired Feature'
STOPHERE
STOPHERE
OnEndExecute
GetFieldDescriptions Count: 89 instead of: 90
PopBusy 'Paired Feature'
finally‍‍‍‍‍‍‍‍‍‍‍‍‍‍

The FieldDefinitions variable from line 45 has been initialized with a call to GetFieldDescriptions prior calling this procedure. 

Line 47 is my workaround to this bug. However line 74 still shows that the bug exists in this piece of code!

Calling this method three times in sequence for fields "Paired Feature'', "Audit Status" and "Review Reason" I get:

PushBusy 'Paired Feature'
STOPHERE
STOPHERE
OnEndExecute
GetFieldDescriptions Count: 89 instead of: 90
PopBusy 'Paired Feature'
finally
PushBusy 'Audit Status'
STOPHERE
STOPHERE
OnEndExecute
GetFieldDescriptions Count: 89 instead of: 91
PopBusy 'Audit Status'
finally
PushBusy 'Review Reason'
STOPHERE
STOPHERE
OnEndExecute
GetFieldDescriptions Count: 89 instead of: 92
PopBusy 'Review Reason'
finally
0 Kudos