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);
}
本质上就是标题所说的内容,无论出于何种原因,当我调用 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);
}