SystemOutOfMemoryException 同时使用 OutlookServicesClient

本文关键字:OutlookServicesClient SystemOutOfMemoryException | 更新日期: 2023-09-27 18:33:00

我最近开始使用新的Outlook/Office 365 Rest API,并在身份验证(新的v2.0应用程序模型),范围,使用OutlookServicesClient和编写更好的(linq-)查询方面得到了一些很好的帮助。

不幸的是,一些用户报告了一些内存问题,这导致了以下System.OutOfMemoryException

    Exception of type 'System.OutOfMemoryException' was thrown. :    at Microsoft.OData.Core.Json.JsonReader.ReadInput()
       at Microsoft.OData.Core.Json.JsonReader.ParseStringPrimitiveValue(Boolean& hasLeadingBackslash)
       at Microsoft.OData.Core.Json.JsonReader.ParseValue()
       at Microsoft.OData.Core.Json.JsonReader.Read()
       at Microsoft.OData.Core.Json.BufferingJsonReader.ReadInternal()
       at Microsoft.OData.Core.Json.BufferingJsonReader.ReadNextAndCheckForInStreamError()
       at Microsoft.OData.Core.Json.BufferingJsonReader.ReadInternal()
       at Microsoft.OData.Core.Json.BufferingJsonReader.Read()
       at Microsoft.OData.Core.JsonLight.ODataJsonLightDeserializer.ParseProperty(DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, Func`2 readPropertyAnnotationValue, String& parsedPropertyName)
       at Microsoft.OData.Core.JsonLight.ODataJsonLightDeserializer.ProcessProperty(DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, Func`2 readPropertyAnnotationValue, Action`2 handleProperty)
       at Microsoft.OData.Core.JsonLight.ODataJsonLightPropertyAndValueDeserializer.ReadComplexValue(IEdmComplexTypeReference complexValueTypeReference, String payloadTypeName, SerializationTypeNameAnnotation serializationTypeNameAnnotation, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker)
       at Microsoft.OData.Core.JsonLight.ODataJsonLightPropertyAndValueDeserializer.ReadNonEntityValueImplementation(String payloadTypeName, IEdmTypeReference expectedTypeReference, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, CollectionWithoutExpectedTypeValidator collectionValidator, Boolean validateNullValue, Boolean isTopLevelPropertyValue, Boolean insideComplexValue, String propertyName, Nullable`1 isDynamicProperty)
       at Microsoft.OData.Core.JsonLight.ODataJsonLightEntryAndFeedDeserializer.ReadEntryDataProperty(IODataJsonLightReaderEntryState entryState, IEdmProperty edmProperty, String propertyTypeName)
       at Microsoft.OData.Core.JsonLight.ODataJsonLightEntryAndFeedDeserializer.ReadEntryPropertyWithValue(IODataJsonLightReaderEntryState entryState, String propertyName)
       at Microsoft.OData.Core.JsonLight.ODataJsonLightEntryAndFeedDeserializer.<>c__DisplayClass2.<ReadEntryContent>b__0(PropertyParsingResult propertyParsingResult, String propertyName)
       at Microsoft.OData.Core.JsonLight.ODataJsonLightDeserializer.ProcessProperty(DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, Func`2 readPropertyAnnotationValue, Action`2 handleProperty)
       at Microsoft.OData.Core.JsonLight.ODataJsonLightEntryAndFeedDeserializer.ReadEntryContent(IODataJsonLightReaderEntryState entryState)
       at Microsoft.OData.Core.JsonLight.ODataJsonLightReader.ReadEntryStart(DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, SelectedPropertiesNode selectedProperties)
       at Microsoft.OData.Core.JsonLight.ODataJsonLightReader.ReadAtEntryEndImplementationSynchronously()
       at Microsoft.OData.Core.JsonLight.ODataJsonLightReader.ReadAtEntryEndImplementation()
       at Microsoft.OData.Core.ODataReaderCore.ReadImplementation()
       at Microsoft.OData.Core.ODataReaderCore.ReadSynchronously()
       at Microsoft.OData.Core.ODataReaderCore.InterceptException[T](Func`1 action)
       at Microsoft.OData.Core.ODataReaderCore.Read()
       at Microsoft.OData.Client.Materialization.ODataReaderWrapper.Read()
       at Microsoft.OData.Client.Materialization.FeedAndEntryMaterializerAdapter.TryRead()
       at Microsoft.OData.Client.Materialization.FeedAndEntryMaterializerAdapter.TryStartReadFeedOrEntry()
       at Microsoft.OData.Client.Materialization.FeedAndEntryMaterializerAdapter.TryReadEntry(MaterializerEntry& entry)
       at Microsoft.OData.Client.Materialization.FeedAndEntryMaterializerAdapter.<LazyReadEntries>d__0.MoveNext()
       at Microsoft.OData.Client.Materialization.FeedAndEntryMaterializerAdapter.Read()
       at Microsoft.OData.Client.Materialization.ODataReaderEntityMaterializer.ReadNextFeedOrEntry()
       at Microsoft.OData.Client.Materialization.ODataEntityMaterializer.ReadImplementation()
       at Microsoft.OData.Client.MaterializeAtom.MoveNextInternal()
       at Microsoft.OData.Client.MaterializeAtom.MoveNext()
       at System.Linq.Enumerable.<CastIterator>d__94`1.MoveNext()
       at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
       at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
       at Microsoft.OData.ProxyExtensions.PagedCollection`2..ctor(DataServiceContextWrapper context, QueryOperationResponse`1 qor)
       at Microsoft.OData.ProxyExtensions.DataServiceContextWrapper.<>c__DisplayClass38`2.<ExecuteAsync>b__36(IAsyncResult r)
       at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)
    --- End of stack trace from previous location where exception was thrown ---
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       at Microsoft.OData.ProxyExtensions.DataServiceContextWrapper.<ExecuteAsync>d__3a`2.MoveNext()
    --- End of stack trace from previous location where exception was thrown ---
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)
       at Shared.Data.Office365.Office365Api.<GetEmailsReceived>d__23.MoveNext()

我的查询(获取某个日期收到的电子邮件数量)如下所示:

var dtStart = date.Date.ToUniversalTime();
var dtEnd = date.Date.AddDays(1).ToUniversalTime();
var mailResults = await _client.Me.Messages
    .OrderByDescending(m => m.ReceivedDateTime)
    .Where(m => m.ReceivedDateTime.Value >= dtStart && m.ReceivedDateTime.Value <= dtEnd)
    //todo: filter if not in Junk Email and Deleted Folder (maybe with ParentFolderId)
    .Take(500) // todo: add paging to (and maybe make more efficient?)
    .Select(m => new DisplayEmail(m)).ExecuteAsync();
// todo: add paging to (and maybe make more efficient?)
foreach (var message in mailResults.CurrentPage)
{
    emails.Add(message);
}

我没有找到处理源的方法,也不认为这是必要的,因为只有局部变量。然后,emails -list 的结果将存储在数据库中。在我添加此功能之前,我的工具的内存使用量是稳定的,现在以每小时 10Mb 左右的速度增长(取决于某人拥有的电子邮件数量)。

任何建议都非常感谢!

SystemOutOfMemoryException 同时使用 OutlookServicesClient

你可以在这里尝试一些事情:

  • 减小页面大小。你在这里一次做 500 个(.Take(500)),你可以尝试减少它。
  • 仅请求您感兴趣的属性。如果您修改.Select以引用m变量的特定属性,则 API 应在 API 请求中使用$select查询参数来限制返回的内容。有关示例,请参阅本教程。