locked
A second operation started on this context before a previous asynchronous operation completed. RRS feed

  • Question

  • User-1350042179 posted

    I receive the error:

    A second operation started on this context before a previous asynchronous operation completed. Use 'await' to ensure that any asynchronous operations have completed before calling another method on this context. Any instance members are not guaranteed to be thread safe

    I have this code..

    [HttpPost, Route("ObtenerFacturasFisicasPaginadoBandeja")]
            [AuthorizationApi]
            public async Task<IHttpActionResult> ObtenerFacturasFisicasPaginadoBandeja(
                BusquedaPaginadaDto<FacturaBusquedaDto> request)
            {
                var idUsuario = (await ObtenerIdUsuarioPorToken()).Id;
                request.Filtro.IdEstado = null;
                var resultado = facturacionAppService.ObtenerFacturasFisicasPaginado(request);
                var usuario = seguridadAppService.ObtenerUsuarioPorId(idUsuario);
    
                await Task.WhenAll(resultado, usuario);
                var resultadoResult = resultado.Result;
                var usuarioResult = usuario.Result;
    
    
            request.Filtro.EsProveedor = usuarioResult.IdProveedor.HasValue;
                request.Filtro.IdTipoResponsable = usuarioResult.EsResponsableDT ? usuarioResult.IdTipoResponsable : null;
                resultadoResult.Listado.ForEach(o => {
                    o.PuedeEliminar = usuarioResult.EsAdministradorCuentasPorPager && (o.IdEstado==Constantes.EstadoComprobante.Pendiente || o.IdEstado==Constantes.EstadoComprobante.Rechazado);
                });
                return Ok(resultadoResult);
            }

    The error is in the line:

    await Task.WhenAll(resultado, usuario);

    I don't know since... 

    facturacionAppService.ObtenerFacturasFisicasPaginado(request) and
    seguridadAppService.ObtenerUsuarioPorId(idUsuario) are awaitable.
    
    Saturday, September 14, 2019 6:07 PM

Answers

  • User-1350042179 posted

    I discovered the problem...

    It is when we call the same table at the same time in a method,,,

    For instance,...

    I have these statements,,,

     var listadoOc =  ordenCompraRepository.ObtenerOrdenCompraPorProveedorEmpresa(idProveedor.Value, idEmpresa);
     var listadoPedido = ordenPedidoRepository.ObtenerOrdenPedidoPorProveedorEmpresa(idProveedor.Value, idEmpresa);
    
    Task.WhenAll(listadoOc,listadoPedido)

    Both call the same table..: ParametroValor

    The first statement: ObtenerOrdenCompraPorProveedorEmpresa

      var query = await (from oc in context.OrdenCompra
                                   join pvmo in context.ParametroValor on oc.IdMoneda equals pvmo.Valor1
                                   join pvcp in context.ParametroValor on oc.IdCondicionPago equals pvcp.Valor1 into pvoc
                                   from copa in pvoc.DefaultIfEmpty()
                                   where oc.IdProveedor == idProveedor && oc.IdEmpresa == idEmpresa &&
                                        oc.IdComprobante == null
                                   select new
                                   {
                                       oc.Id,
                                       NombreEmpresa = oc.Empresa.Nombre,
                                       oc.NumeroOrdenCompra,
                                       oc.ClasePedido,
                                       oc.NumeroDocumentoReferencia,
                                       oc.FechaContabilizacion,
                                       oc.BaseImponible,
                                       Moneda = pvmo.Nombre,
                                       IdMoneda = pvmo.Id,
                                       oc.IndicadorIva,
                                       IdFacturaRelacionada = oc.IdComprobante,
                                       CondicionPago = copa.Nombre,
                                       oc.Posicion
                                   })
                                   .OrderBy(x => x.NumeroOrdenCompra).ThenByDescending(y => y.FechaContabilizacion)
                                   .ToListAsync();

    The second:ObtenerOrdenPedidoPorProveedorEmpresa

    var query = (from oc in context.OrdenPedido
                             join pvmo in context.ParametroValor on oc.IdMoneda equals pvmo.Valor1
                             join pvem in context.ParametroValor on oc.IdEmpresa equals pvem.Id
                             join pvcp in context.ParametroValor on oc.IdCondicionPago equals pvcp.Valor1 into pvoc
                             from copa in pvoc.DefaultIfEmpty()
                             where oc.IdProveedor == idProveedor && oc.IdEmpresa == idEmpresa &&
                                 oc.IdComprobante == null
                             select new
                             {
                                 oc.Id,
                                 NombreEmpresa = pvem.Nombre,
                                 oc.CodigoOP,
                                 oc.ClasePedido,
                                 oc.IdCondicionPago,
                                 oc.FechaCreacionOP,
                                 oc.BaseImponible,
                                 Moneda = pvmo.Nombre,
                                 IdMoneda = pvmo.Id,
                                 oc.IndicadorIva,
                                 oc.NumeroIdentificacionFiscal,
                                 IdFacturaRelacionada = oc.IdComprobante,
                                 oc.Posicion,
                                 CondicionPago = copa.Nombre
                             })
                            .OrderBy(x => x.CodigoOP).ThenByDescending(y => y.FechaCreacionOP)
                            .ToList();

    I use 

    Lifestyle.Scoped
    

    So the context is the same in both operations. I think to use Lifestyle.Transient but I creates a scope when it needs.

    I solved it using awaits.

       var listadoOc = await ordenCompraRepository.ObtenerOrdenCompraPorProveedorEmpresa(idProveedor.Value, idEmpresa);
       var listadoPedido = await ordenPedidoRepository.ObtenerOrdenPedidoPorProveedorEmpresa(idProveedor.Value, idEmpresa);
    
       return new Tuple<List<OrdenCompraFacturaRegistroDto>, List<OrdenPedidoFacturaRegistroDto>>(
                        listadoOc, listadoPedido);



    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Friday, November 1, 2019 9:44 PM

All replies

  • User-1350042179 posted

    Hi

    I identify that each method calls others methods so a method has to wait the response of others methods.

    The solution is that task.whenall has to call  only methods which don't call other methods.

    Sunday, September 15, 2019 12:06 AM
  • User61956409 posted

    Hi neoaguil17,

    I identify that each method calls others methods so a method has to wait the response of others methods.

    The solution is that task.whenall has to call  only methods which don't call other methods.

    It seems that you have already solved the issue by yourself, do you use 'await' on them or create and use multiple contexts for calling these two methods?

    With Regards,

    Fei Han

    Monday, September 16, 2019 6:41 AM
  • User-474980206 posted

    Hi

    I identify that each method calls others methods so a method has to wait the response of others methods.

    The solution is that task.whenall has to call  only methods which don't call other methods.

    this is not strictly true. WhenAll allows multiple async calls to run at the same time. a restriction of dbcontext is that it can not be used with two async calls at the same time. thus is two async calls use the same dbcontext, then you can  not use a WhenAll, but must serialize them with awaits.

    Monday, September 16, 2019 3:17 PM
  • User-1350042179 posted

    I discovered the problem...

    It is when we call the same table at the same time in a method,,,

    For instance,...

    I have these statements,,,

     var listadoOc =  ordenCompraRepository.ObtenerOrdenCompraPorProveedorEmpresa(idProveedor.Value, idEmpresa);
     var listadoPedido = ordenPedidoRepository.ObtenerOrdenPedidoPorProveedorEmpresa(idProveedor.Value, idEmpresa);
    
    Task.WhenAll(listadoOc,listadoPedido)

    Both call the same table..: ParametroValor

    The first statement: ObtenerOrdenCompraPorProveedorEmpresa

      var query = await (from oc in context.OrdenCompra
                                   join pvmo in context.ParametroValor on oc.IdMoneda equals pvmo.Valor1
                                   join pvcp in context.ParametroValor on oc.IdCondicionPago equals pvcp.Valor1 into pvoc
                                   from copa in pvoc.DefaultIfEmpty()
                                   where oc.IdProveedor == idProveedor && oc.IdEmpresa == idEmpresa &&
                                        oc.IdComprobante == null
                                   select new
                                   {
                                       oc.Id,
                                       NombreEmpresa = oc.Empresa.Nombre,
                                       oc.NumeroOrdenCompra,
                                       oc.ClasePedido,
                                       oc.NumeroDocumentoReferencia,
                                       oc.FechaContabilizacion,
                                       oc.BaseImponible,
                                       Moneda = pvmo.Nombre,
                                       IdMoneda = pvmo.Id,
                                       oc.IndicadorIva,
                                       IdFacturaRelacionada = oc.IdComprobante,
                                       CondicionPago = copa.Nombre,
                                       oc.Posicion
                                   })
                                   .OrderBy(x => x.NumeroOrdenCompra).ThenByDescending(y => y.FechaContabilizacion)
                                   .ToListAsync();

    The second:ObtenerOrdenPedidoPorProveedorEmpresa

    var query = (from oc in context.OrdenPedido
                             join pvmo in context.ParametroValor on oc.IdMoneda equals pvmo.Valor1
                             join pvem in context.ParametroValor on oc.IdEmpresa equals pvem.Id
                             join pvcp in context.ParametroValor on oc.IdCondicionPago equals pvcp.Valor1 into pvoc
                             from copa in pvoc.DefaultIfEmpty()
                             where oc.IdProveedor == idProveedor && oc.IdEmpresa == idEmpresa &&
                                 oc.IdComprobante == null
                             select new
                             {
                                 oc.Id,
                                 NombreEmpresa = pvem.Nombre,
                                 oc.CodigoOP,
                                 oc.ClasePedido,
                                 oc.IdCondicionPago,
                                 oc.FechaCreacionOP,
                                 oc.BaseImponible,
                                 Moneda = pvmo.Nombre,
                                 IdMoneda = pvmo.Id,
                                 oc.IndicadorIva,
                                 oc.NumeroIdentificacionFiscal,
                                 IdFacturaRelacionada = oc.IdComprobante,
                                 oc.Posicion,
                                 CondicionPago = copa.Nombre
                             })
                            .OrderBy(x => x.CodigoOP).ThenByDescending(y => y.FechaCreacionOP)
                            .ToList();

    I use 

    Lifestyle.Scoped
    

    So the context is the same in both operations. I think to use Lifestyle.Transient but I creates a scope when it needs.

    I solved it using awaits.

       var listadoOc = await ordenCompraRepository.ObtenerOrdenCompraPorProveedorEmpresa(idProveedor.Value, idEmpresa);
       var listadoPedido = await ordenPedidoRepository.ObtenerOrdenPedidoPorProveedorEmpresa(idProveedor.Value, idEmpresa);
    
       return new Tuple<List<OrdenCompraFacturaRegistroDto>, List<OrdenPedidoFacturaRegistroDto>>(
                        listadoOc, listadoPedido);



    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Friday, November 1, 2019 9:44 PM