SharePoint CSOM 未在 ExecuteQuery 上引发预期的异常

SharePoint CSOM not throwing expected exceptions on ExecuteQuery

本质上就是标题所说的内容,无论出于何种原因,当我调用 clientContext.ExecuteQuery(); 时,例如数据要进入的列表中缺少一列,我没有得到异常,它实际上只是运行预期,我必须去调查可能导致数据不显示的原因。

我使用的 NuGet 包是 Microsoft.SharePoint2016.CSOM 版本 16.0.4690.1000

任何提示或建议都可以为我指明正确的方向,不胜感激。完全有可能我在这里有点暗淡。

这是我用于更新列表项的完整代码块:

public override object UpdateEntity(object entity)
{
    if (entity == null)
    {
        // if the definition is null throw argument null exception.
        throw new ArgumentNullException(nameof(SharePointDefinition));
    }

    // check for incorrect type being passed in that we can still handle
    if (entity is List<SharePointDefinition> definitions)
    {
        return UpdateEntities(definitions);
    }

    ExceptionHandlingScope exceptionScopeFetch = new ExceptionHandlingScope(clientContext);
    ExceptionHandlingScope exceptionScopeSubmit = new ExceptionHandlingScope(clientContext);

    // run single definition submit to SP.
    if (entity is SharePointDefinition definition)
    {
        // variables.
        IntegrationEventLog log = new IntegrationEventLog();
        EventInformation ei = new EventInformation();
        List list = null;
        ListItemCollection listItemCol = null;

        using (exceptionScopeFetch.StartScope())
        {
            using (exceptionScopeFetch.StartTry())
            {
                // get the required list
                list = clientContext.Web.Lists.GetByTitle(definition.ListName);

                // create query
                listItemCol = list.GetItems(CamlQuery.CreateAllItemsQuery());

                // set these items for retrieval.
                clientContext.Load(listItemCol);
            }

            using (exceptionScopeFetch.StartCatch())
            {
                // Assume that if there's an exception, it can only be 
                // because there is no list with the specified title, so report this back.
                if (exceptionScopeFetch.HasException)
                {
                    ei = new EventInformation()
                    {
                        LoggingEventType = LoggingEventType.DataSentFailure,
                        LoggingSeverity = LoggingSeverity.HighSeverity,
                        SerialisedMessage = JsonConvert.SerializeObject(definition),
                        ServiceMessage = $"Hit SharePoint exception handler during list and data pull: Message: {exceptionScopeFetch.ErrorMessage}",
                        StackTrace = exceptionScopeFetch.ServerStackTrace,
                        TimeGenerated = DateTime.Now,
                        TimeWritten = DateTime.Now,
                    };

                    log.EventLogEntryType = EventLogEntryType.Error;
                    log.EventID = LoggingSeverity.HighSeverity;
                    log.Message = JsonConvert.SerializeObject(ei);
                    AddToLog(log);
                }
            }

            using (exceptionScopeFetch.StartFinally())
            {
                //
            }
        }

        // get item instances first
        try
        {
            clientContext.ExecuteQuery();
        }
        catch (Exception genEx)
        {
            // return failure log.
            ei = new EventInformation()
            {
                LoggingEventType = LoggingEventType.DataSentFailure,
                LoggingSeverity = LoggingSeverity.HighSeverity,
                SerialisedMessage = JsonConvert.SerializeObject(definition),
                ServiceMessage = "Errored trying to get data from SharePoint list ready for update operation; see stacktrace for more information.",
                StackTrace = genEx.StackTrace,
                TimeGenerated = DateTime.Now,
                TimeWritten = DateTime.Now,
            };

            log.EventLogEntryType = EventLogEntryType.Error;
            log.EventID = LoggingSeverity.HighSeverity;
            log.Message = JsonConvert.SerializeObject(ei);
            AddToLog(log);

            return false;
        }

        // this is the column we want to overwrite.
        var comparisonColumn = definition.UpdateIdentifier ?? "";

        //List col to dict
        var listItems = listItemCol.Cast<ListItem>().ToList();

        // Now we know if we were able to retrieve existing data, perform submit.
        using (exceptionScopeSubmit.StartScope())
        {
            using (exceptionScopeSubmit.StartTry())
            {
                // loop through our rows
                foreach (var row in definition.RowData)
                {
                    int existingItemIndex = -1;
                    // see if the row exists already
                    if (!string.IsNullOrEmpty(comparisonColumn) && listItems.Count != 0)
                    {
                        existingItemIndex = listItems.FindIndex(x => x[comparisonColumn].ToString() == row[comparisonColumn]);
                    }

                    if (existingItemIndex != -1 && listItems.Count != 0)
                    {
                        // item exists - loop through our row columns
                        foreach (var keyValuePair in row)
                        {
                            // they key relates to a column, the Value to the rows colum Value.
                            listItems[existingItemIndex].ParseAndSetFieldValue(keyValuePair.Key, keyValuePair.Value);
                        }

                        // update this item
                        listItems[existingItemIndex].Update();
                    }
                    else
                    {
                        ListItemCreationInformation itemCreateInfo = new ListItemCreationInformation();
                        ListItem newItem = list.AddItem(itemCreateInfo);

                        // loop through our row columns
                        foreach (var keyValuePair in row)
                        {
                            // they key relates to a column, the Value to the rows colum Value.
                            newItem[keyValuePair.Key] = keyValuePair.Value;
                        }
                        newItem.Update();
                    }
                }
            }

            using (exceptionScopeSubmit.StartCatch())
            {
                // Assume that if there's an exception, it can only be 
                // because there is no list with the specified title, so report this back.
                if (exceptionScopeFetch.HasException)
                {
                    ei = new EventInformation()
                    {
                        LoggingEventType = LoggingEventType.DataSentFailure,
                        LoggingSeverity = LoggingSeverity.HighSeverity,
                        SerialisedMessage = JsonConvert.SerializeObject(definition),
                        ServiceMessage = $"Error at SharePoint exception handler during submit to list: Message: {exceptionScopeFetch.ErrorMessage}",
                        StackTrace = exceptionScopeFetch.ServerStackTrace,
                        TimeGenerated = DateTime.Now,
                        TimeWritten = DateTime.Now,
                    };

                    log.EventLogEntryType = EventLogEntryType.Error;
                    log.EventID = LoggingSeverity.HighSeverity;
                    log.Message = JsonConvert.SerializeObject(ei);
                    AddToLog(log);
                }
            }

            using (exceptionScopeSubmit.StartFinally())
            {
                //
            }
        }

        // try to execute submit.
        try
        {
            clientContext.ExecuteQuery();

            ei = new EventInformation()
            {
                LoggingEventType = LoggingEventType.DataSentSuccess,
                LoggingSeverity = LoggingSeverity.Information,
                SerialisedMessage = JsonConvert.SerializeObject(definition),
                ServiceMessage = "No exceptions were thrown from the Execution process.",
                StackTrace = "",
                TimeGenerated = DateTime.Now,
                TimeWritten = DateTime.Now,
            };

            log.EventLogEntryType = EventLogEntryType.Information;
            log.EventID = LoggingSeverity.Information;
            log.Message = JsonConvert.SerializeObject(ei);
        }
        catch (Exception genEx)
        {
            ei = new EventInformation()
            {
                LoggingEventType = LoggingEventType.DataSentFailure,
                LoggingSeverity = LoggingSeverity.HighSeverity,
                SerialisedMessage = JsonConvert.SerializeObject(definition),
                ServiceMessage = $"Data failed to be updated within SharePoint - {genEx.Message} - see stacktrace for more information.",
                StackTrace = genEx.StackTrace,
                TimeGenerated = DateTime.Now,
                TimeWritten = DateTime.Now,
            };

            log.EventLogEntryType = EventLogEntryType.Error;
            log.EventID = LoggingSeverity.HighSeverity;
            log.Message = JsonConvert.SerializeObject(ei);
            AddToLog(log);

            return false;
        }

        AddToLog(log);
        return true;
    }
    else
    {
        // If a different definition type is passed in throw an appropriate exception. 
        // This should be caught at runtime only.
        throw new TypeLoadException(nameof(SharePointDefinition));
    }
}

我检查了您发布的代码,发现您正在更新对象列表,在您的例子中是 listItems,而不是 ListItemCollection[ 中的 ListItem =22=],在你的例子中是 listItemCol。 为了更清楚,我相信你可以尝试将 listItems 替换为 listItemCol。 例如,而不是:

listItems[existingItemIndex].ParseAndSetFieldValue(keyValuePair.Key, keyValuePair.Value);

使用

listItemCol[existingItemIndex][keyValuePair.Key] = keyValuePair.Value;

所以我离开并重新阅读了大量文档并查看了一些示例,我想知道为什么异常处理程序从未返回错误,即使执行的查询很明显存在问题。如果您查看 Microsoft 文档及其示例 here,您会发现它们没有向您展示如何使用异常范围对象的 exceptionScopeSubmit.HasException 组件。这导致我做出了一个非常愚蠢的假设。事实证明,异常块在 SharePoint 服务器上运行,应该用于修复您可能在查询中的预期异常期间引起的问题。

不仅如此,在使用异常作用域时,将 ExecuteQuery 包装在 try catch 中也是多余的,因为这意味着该方法将不再抛出异常。实际上,您必须在执行后评估 exceptionScopeSubmit.HasException 以提取有关 SharePoint 服务器端执行查询所报告的错误的更多详细信息。

所以现在我如下使用它,我可以获得详细的错误信息,而不必进行一些愚蠢的手动调试,这很容易让我花费数小时来追踪愚蠢的问题。因此,如果有人遇到同样的问题,希望对您有所帮助。

ExceptionHandlingScope exceptionScopeFetch = new ExceptionHandlingScope(clientContext);

// variables.
IntegrationEventLog log = new IntegrationEventLog();
EventInformation ei = new EventInformation();
List list = null;
ListItemCollection listItemCol = null;

using (exceptionScopeFetch.StartScope())
{
    using (exceptionScopeFetch.StartTry())
    {
        // get the required list
        list = clientContext.Web.Lists.GetByTitle(definition.ListName);

        // create query
        listItemCol = list.GetItems(CamlQuery.CreateAllItemsQuery());

        // set these items for retrieval.
        clientContext.Load(listItemCol);
    }

    using (exceptionScopeFetch.StartCatch())
    {
        //
    }

    using (exceptionScopeFetch.StartFinally())
    {
        //
    }
}

// get item instances first
clientContext.ExecuteQuery();
    
if (exceptionScopeSubmit.HasException)
{
    ei = new EventInformation()
    {
        LoggingEventType = LoggingEventType.DataSentFailure,
        LoggingSeverity = LoggingSeverity.HighSeverity,
        SerialisedMessage = JsonConvert.SerializeObject(definition),
        ServiceMessage = $"Error at SharePoint exception handler during submit to list: Message: {exceptionScopeFetch.ErrorMessage}",
        StackTrace = exceptionScopeFetch.ServerStackTrace,
        TimeGenerated = DateTime.Now,
        TimeWritten = DateTime.Now,
    };

    log.EventLogEntryType = EventLogEntryType.Error;
    log.EventID = LoggingSeverity.HighSeverity;
    log.Message = JsonConvert.SerializeObject(ei);
    AddToLog(log);
}