Beaucoup d'exceptions d'agrégation imbriquées

aggregateexception async-await c# entity-framework-core

Question

En travaillant avec Entity Framework 7, j'ai fait une simple erreur avec un linq (utilisé Skip et j'ai oublié d'inclure ma clause OrderBy).

L'exception qui a été levée par cela incluait un certain nombre d'exceptions globales imbriquées.

Le code qui génère (et capture) l'exception est:

int[] newIds;
try
{
    newIds = await db.Products
        .Where(p => p.PortalId == portalId)
        .Skip(ids.ProductIds.Count) //Skip the rows already read
        .Take(takeTotal) //get the next block
        .Select(p => p.ProductId)
        .ToArrayAsync();
}
catch (AggregateException ex)
{
    Console.WriteLine(ex.Message);
    newIds = new int[] { };
}

Le code ci-dessus est dans une classe de référentiel appelée à partir d'un contrôleur WebApi Asp.Net 5. Tous les niveaux de l'appel utilisent async-wait.

Cependant, l’exception globale que j’ai tirée de ceci est (celle-ci est transférée dans la fenêtre immédiate du bloc catch présenté ci-dessus):

System.AggregateException: une ou plusieurs erreurs se sont produites. ---> System.AggregateException: une ou plusieurs erreurs se sont produites. ---> System.AggregateException: une ou plusieurs erreurs se sont produites. ---> System.AggregateException: une ou plusieurs erreurs se sont produites. ---> System.AggregateException: une ou plusieurs erreurs se sont produites. ---> System.AggregateException: une ou plusieurs erreurs se sont produites. ---> System.InvalidOperationException: une requête contenant l'opérateur Skip doit inclure au moins une opération OrderBy. sur Microsoft.Data.Entity. .Expressions.SelectExpression.Accept (visiteur ExpressionTreeVisitor) chez Microsoft.Data.Entity.Relational.Query.Sql.DefaultSqlQueryGenerator.GenerateSql (SelectExpression selectExpression, IDictionary`2 paramètreValues), etc.

Ici, l'exception réelle a été enveloppée par un tas de couches d'exception globale (6 couches imbriquées). Je comprends pourquoi je reçois une exception globale, mais je me demandais pourquoi il y en avait autant? D'autant plus que je suis en train de regarder l'exception avant qu'elle ne remonte au point d'entrée du contrôleur.

Cela résulterait-il d'un certain nombre de couches d'attente asynchrone (ne pensez pas que j'en ai autant que 6) ou pourrait-il s'agir d'un problème dans la mise en œuvre de EF7?

Ceci utilise actuellement EF 7 release 7.0.0-beta4.

Réponse acceptée

Comme l' explique la page MSDN de la Task<T> , toutes les exceptions levées par une Task sont encapsulées dans AggregateException avant d'être renvoyées au code en attente. Si vous utilisez plusieurs niveaux d'async / wait sans capturer cette exception au niveau le plus bas possible, chaque fois qu'il monte d'un niveau supérieur, il est de nouveau encapsulé, ce qui conduit à AggregateException dans AggregateException , un pour chaque fois que vous ' attendre sans attraper.

Il se peut également que chaque opération soit considérée comme une tâche propre; c'est à dire. chaque fois que vous ajoutez une autre opération, le résultat sort de la précédente et redescend dans la suivante, chacune attendant la précédente. Regarde:

newIds = await db.Products               // 1
    .Where(p => p.PortalId == portalId)  // 2
    .Skip(ids.ProductIds.Count)          // 3
    .Take(takeTotal)                     // 4
    .Select(p => p.ProductId)            // 5
    .ToArrayAsync();                     // 6

Six couches de choses, chacune attendant le résultat de la précédente. Six couches AggregateException . Votre exception est causée par le troisième des six problèmes, mais de par la nature de l'erreur, il est probable qu'elle provienne d'une partie où EF lit l'intégralité de votre requête avant de l'exécuter, ce qui vous fait remarquer que vous ' .Skip() un .Skip() sans un .OrderBy() .

Comme Stephen Cleary me l'a rappelé dans les commentaires, pendant que vous await retour de la Task<T> , ils effectuent également un certain degré de déballage pour vous. await ne se comporte donc pas tout à fait comme la Task<T>.Result , ce qui signifie que l' await doit exception réelle sans l'envelopper dans AggregateException . Tout ce que cela signifie, c'est qu'au mieux, nous n'avons que la moitié de la réponse ici (ce qui est un peu gênant, vu que cela a déjà été accepté). Honnêtement, je vous suggérerais de ne pas accepter cette réponse afin que les autres ne sautent pas votre question et voient si quelqu'un d'autre sait quelque chose qui pourrait combler les lacunes.


Réponse populaire

Ce n'est pas lié à la quantité de méthode appelée dans la chaîne. Il vous suffit d'appeler ToArrayAsync.

Je pense que le problème est dans Rx.NET. J'ai envoyé une demande d'extraction pour y remédier: https://github.com/aspnet/EntityFramework/issues/2192

https://github.com/Reactive-Extensions/Rx.NET/pull/131/files



Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi