1

J'ai récemment commencé à utiliser le nouveau Outlook/Office 365 API Rest et ai une grande aide en ce qui concerne la authentication (nouveau modèle d'application v2.0), scopes, en utilisant le OutlookServicesClient et écrire mieux (linq-)queries.SystemOutOfMemoryException tout en utilisant le OutlookServicesClient

Malheureusement, certains utilisateurs ont signalé des problèmes de mémoire, ce qui a entraîné la System.OutOfMemoryException suivante:

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() 

Ma requête (pour obtenir le nombre de courriels reçus pour une date) ressemble à ceci:

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); 
} 

Je n'ai pas trouvé un moyen de disposer des sources et je ne pense pas que ce soit nécessaire, car il n'y a que des variables locales. Le résultat de la liste emails est ensuite stocké dans la base de données. L'utilisation de la mémoire pour mon outil était stable avant que j'ajoute cette fonctionnalité, et augmente maintenant à environ 10 Mo par heure (selon le nombre de courriels de quelqu'un).

Toutes les suggestions sont très appréciées!

+0

Si vous avez juste besoin du nombre de courriels reçus à une date, avez-vous besoin de les stocker? Cela permettrait probablement d'économiser beaucoup de temps et d'espace. –

+0

Non, je n'en ai pas besoin. Mais qu'est-ce que j'ai besoin de changer? Merci! – casaout

Répondre

2

Vous pouvez essayer quelques petites choses ici:

  • Réduire la taille de votre page. Vous faites 500 à la fois ici (.Take(500)), vous pourriez essayer de réduire cela.
  • Ne demandez que les propriétés qui vous intéressent. Si vous modifiez votre .Select pour référencer les propriétés spécifiques de votre variable m, l'API doit utiliser un paramètre de requête $select dans la demande d'API pour limiter ce qui revient. Voir this tutorial pour un exemple.
+0

Merci Jason! Même si je viens de sélectionner quelques propriétés dans l'instruction Select, je peux les supprimer toutes car je n'en ai pas besoin pour les compter. En outre, j'ai maintenant mis en place la pagination appropriée (et réduit le Take (500) à prendre (20). Je viens de publier la mise à jour et espère que cela résout tous les problèmes de mémoire pour les utilisateurs. – casaout