Muchas excepciones agregadas anidadas

aggregateexception async-await c# entity-framework-core

Pregunta

Al trabajar con Entity Framework 7, cometí un simple error con algunos linq (usé Omitir y olvidé incluir mi cláusula OrderBy).

La excepción que fue lanzada por esto incluyó un número de excepciones agregadas anidadas.

El código que genera (y captura) la excepción es:

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[] { };
}

El código anterior está en una clase de repo llamada desde un controlador Asp.Net 5 WebApi. Todos los niveles de la llamada están utilizando async-await.

Sin embargo, la excepción agregada que obtuve de esto fue (esto se descarga en la ventana inmediata desde el bloque de captura que se muestra arriba):

System.AggregateException: se produjeron uno o más errores. ---> System.AggregateException: Se produjeron uno o más errores. ---> System.AggregateException: Se produjeron uno o más errores. ---> System.AggregateException: Se produjeron uno o más errores. ---> System.AggregateException: Se produjeron uno o más errores. ---> System.AggregateException: Se produjeron uno o más errores. ---> System.InvalidOperationException: una consulta que contenga el operador Skip debe incluir al menos una operación OrderBy. at Microsoft.Data.Entity.Relational.Query.Sql.DefaultSqlQueryGenerator.GenerateLimitOffset (SelectExpression selectExpression) en Microsoft.Data. .Expressions.SelectExpression.Accept (visitante de ExpressionTreeVisitor) en Microsoft.Data.Entity.Relational.Query.Sql.DefaultSqlQueryGenerator.GenerateSql (SelectExpression selectExpression, IDictionary`2 parámetroValues) etc. etc.

Aquí, la excepción real terminó envuelta por un conjunto completo de capas de excepción agregada (6 capas anidadas). Entiendo por qué recibo una excepción agregada, pero me pregunto por qué tantos de ellos. Más aún, ya que estoy viendo la excepción antes de que haya regresado al punto de entrada del controlador.

¿Sería esto el resultado de una serie de capas de async-await (no creo que tenga tantas como 6) o podría ser un problema en la implementación de EF7?

Actualmente se está utilizando la versión 7.0.0-beta4 de EF 7.

Respuesta aceptada

Como lo explica la página de MSDN en la Task<T> , todas las excepciones lanzadas por una Task se envuelven en la excepción AggregateException antes de ser lanzadas al código en espera. Si está utilizando múltiples niveles de async / await y no está capturando esta excepción en el nivel más bajo posible, entonces, cada vez que se infla otro nivel, se envuelve nuevamente, lo que lleva a AggregateException dentro de AggregateException , uno por cada vez que ' Esperando sin atrapar.

También podría ser que cada operación se cuente como su propia tarea; es decir. Cada vez que agrega otra operación, el resultado sale de la anterior y vuelve a la siguiente, con cada una esperando la anterior. Echar un vistazo:

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

Seis capas de cosas, cada una esperando el resultado de la anterior. Seis capas AggregateException excepción. Ahora, su excepción es causada por el tercero de los seis, pero debido a la naturaleza del error, es probable que provenga de una parte en la que EF lee toda su consulta antes de hacer algo, y al hacerlo, se le ve que ' Tengo un .Skip() sin un .OrderBy() coincidente.

Como Stephen Cleary me recordó en los comentarios, mientras las cosas que await devuelven la Task<T> , también hacen un poco de desenvolvimiento para ti, por lo que await no se comporta como la Task<T>.Result , lo que significa que await debería lanzar el excepción real sin envolverla en AggregateException . Lo que todo esto significa es que, en el mejor de los casos, solo tenemos la mitad de la respuesta aquí (lo cual es un poco incómodo, ya que se ha aceptado). Honestamente, sugeriría que no aceptes esta respuesta para que otros no omitan tu pregunta y vean si alguien más sabe algo que pueda llenar los vacíos.


Respuesta popular

No está relacionado con la cantidad de método llamado en cadena. Solo necesitas llamar a ToArrayAsync.

Creo que el problema está en Rx.NET. Envié una solicitud de extracción para solucionarlo: https://github.com/aspnet/EntityFramework/issues/2192

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




Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué