linq查询异步/等待审核

时间:2018-05-28 09:23:29

标签: c# linq async-await

我正在将一个正在运行的linq管道升级到异步,我正在使用synthaxe / logic(在task.run,async / await,Tolist ......)进行一些努力。 目前它不会编译,因为最后一个方法返回IEnumerable的Task产品而不是IEnumerable产品

这是电话:

public async Task<IEnumerable<ProductDto>> GetProducts(bool isLogged)
{
    return await _mapper.GetStripeProductsDto(isLogged, false);
}

其中一个回购:

public async Task<IEnumerable<StripeProduct>> GetAllStripeProductsAsync()
{
    return (await _productService.ListAsync())
        .Where(x => x.Type == "good" && x.Active == true);
}

我在哪里建立我的dto并且正在努力:

    public async Task<IEnumerable<ProductDto>> GetStripeProductsDto(bool isLogged, bool isSubscriber)
    {
        var productList = (await _productRepo.GetAllStripeProductsAsync()).ToList();

        return await Task.Run(async () => 
                GetSkuOffers(productList)
                    .Concat(await GetSubsciptionOffers(productList))
                    .GroupBy(product => product.Name)
                    .Select(productGroup => new ProductDto
                    {
                        Name = productGroup.Key,
                        Id = productGroup.Select(product => product.Id).First(),
                        Description = productGroup.Select(product => product.Description).First(),
                        Image = productGroup.Select(product => product.Image).First(),
                        CurrentUserProfile = isSubscriber
                            ? OfferTypeEnum.Pro.ToString()
                            : isLogged
                                ? OfferTypeEnum.Registered.ToString()
                                : OfferTypeEnum.Basic.ToString(),
                        Prices = productGroup.Select(product => new
                        {
                            Offer = product.OfferType.ToString(),
                            Price = product.Price.ToString()
                        })
                        .ToDictionary(p => p.Offer, p => p.Price)
                    })
                    .ToList())
            .ConfigureAwait(false);
    }

    private IEnumerable<Product> GetSkuOffers(IEnumerable<StripeProduct> productList)
    {
        return productList
            .SelectMany(sku => sku.Skus.Data, (product, sku) => new Product
            {
                Name = product.Name,
                Id = product.Id,
                Image = new Uri(product.Images.First()),
                Description = product.Description,
                OfferType = sku.Id.Contains("Basic") ? OfferTypeEnum.Basic : OfferTypeEnum.Registered,
                Price = sku.Price
            });
    }

    private IEnumerable<Product> GetSubsciptionOffers(IEnumerable<StripeProduct> productList)
    {
        return 
            productList
            .Select(async product => new Product
            {
                Name = product.Name,
                Id = product.Id,
                Image = new Uri(product.Images.First()),
                Description = product.Description,
                OfferType = OfferTypeEnum.Pro,
                Price = (await _planRepo.GetPlanByIdAsync(product.Metadata.First().Value)).Amount.GetValueOrDefault()
            });
    }
编辑:编译版本,ToListAsync似乎只适用于DB,我的repo调用api,所以我放弃了;我删除了Task.Run(...),并以可能令人讨厌的方式摆脱了IEnumerable的任务产品

    public async Task<IEnumerable<ProductDto>> GetStripeProductsDto(bool isLogged, bool isSubscriber)
    {
        var productList = (await _productRepo.GetAllStripeProductsAsync()).ToList();
        var skuOffers = GetSkuOffers(productList);
        var subsciptionOffers = GetSubsciptionOffers(productList);

        return skuOffers
            .Concat(subsciptionOffers)
            .GroupBy(product => product.Name)
            .Select(productGroup => new ProductDto
            {
                Name = productGroup.Key,
                Id = productGroup.Select(product => product.Id).First(),
                Description = productGroup.Select(product => product.Description).First(),
                Image = productGroup.Select(product => product.Image).First(),
                CurrentUserProfile = isSubscriber
                    ? OfferTypeEnum.Pro.ToString()
                    : isLogged
                        ? OfferTypeEnum.Registered.ToString()
                        : OfferTypeEnum.Basic.ToString(),
                Prices = productGroup.Select(product => new
                {
                    Offer = product.OfferType.ToString(),
                    Price = product.Price.ToString()
                })
                .ToDictionary(p => p.Offer, p => p.Price)
            })
            .ToList();
    }

    private IEnumerable<Product> GetSkuOffers(IEnumerable<StripeProduct> productList)
    {
        return productList
            .SelectMany(sku => sku.Skus.Data, (product, sku) => new Product
            {
                Name = product.Name,
                Id = product.Id,
                Image = new Uri(product.Images.First()),
                Description = product.Description,
                OfferType = sku.Id.Contains("Basic") ? OfferTypeEnum.Basic : OfferTypeEnum.Registered,
                Price = sku.Price
            });
    }

    private IEnumerable<Product> GetSubsciptionOffers(IEnumerable<StripeProduct> productList)
    {
        return productList
            .Select(product => new Product
            {
                Name = product.Name,
                Id = product.Id,
                Image = new Uri(product.Images.First()),
                Description = product.Description,
                OfferType = OfferTypeEnum.Pro,
                //Price = _planRepo.GetPlanById(product.Metadata.First().Value).Amount.GetValueOrDefault()
                Price = GetSubscriptionPrice(product.Metadata.First().Value)
            }).ToList();
    }

    private int GetSubscriptionPrice(string str)
    {
        var plan = Task.Run(() => _planRepo.GetPlanByIdAsync(str)).GetAwaiter().GetResult();
        return plan.Amount.GetValueOrDefault();
    }

1 个答案:

答案 0 :(得分:0)

我会做这样的事情:

public async Task<IEnumerable<ProductDto>> GetProductsAsync(bool isLogged)
{
    return await _mapper.GetStripeProductsDto(isLogged, false);
}

public async Task<IEnumerable<StripeProduct>> GetAllStripeProductsAsync()
{
    var list = await _productService.ListAsync();

    return await list.Where(x => x.Type == "good" && x.Active == true).ToListAsync();
}

public async Task<IEnumerable<ProductDto>> GetStripeProductsDtoAsync(bool isLogged, bool isSubscriber)
{
    // here you're making async call and when task is done, you are making .ToList() on results
    var productList = await _productRepo.GetAllStripeProductsAsync();

    // this will be executed when productList has results from database (task).
    // Because GetSkuOffers() method is sync you can execute this like below.
    var skuOffersResult = GetSkuOffers(productList);

    // get asynchronously subscription offers
    var getSubscriptionOffers = await GetSubsciptionOffers(productList);

    // this is done also synchronously so you don't need to use async/await statements
    skuOffersResult.Concat(getSubscriptionOffers)
                .GroupBy(product => product.Name)
                .Select(productGroup => new ProductDto
                {
                    Name = productGroup.Key,
                    Id = productGroup.Select(product => product.Id).First(),
                    Description = productGroup.Select(product => product.Description).First(),
                    Image = productGroup.Select(product => product.Image).First(),
                    CurrentUserProfile = isSubscriber
                        ? OfferTypeEnum.Pro.ToString()
                        : isLogged
                            ? OfferTypeEnum.Registered.ToString()
                            : OfferTypeEnum.Basic.ToString(),
                    Prices = productGroup.Select(product => new
                    {
                        Offer = product.OfferType.ToString(),
                        Price = product.Price.ToString()
                    })
                    .ToDictionary(p => p.Offer, p => p.Price)
                })
                .ToList());
}

private IEnumerable<Product> GetSkuOffers(IEnumerable<StripeProduct> productList)
{
    return productList
        .SelectMany(sku => sku.Skus.Data, (product, sku) => new Product
        {
            Name = product.Name,
            Id = product.Id,
            Image = new Uri(product.Images.First()),
            Description = product.Description,
            OfferType = sku.Id.Contains("Basic") ? OfferTypeEnum.Basic : OfferTypeEnum.Registered,
            Price = sku.Price
        });
}

private async Task<IEnumerable<Product>> GetSubsciptionOffers(IEnumerable<StripeProduct> productList)
{
    return
        productList
        .Select(async product => new Product
        {
            Name = product.Name,
            Id = product.Id,
            Image = new Uri(product.Images.First()),
            Description = product.Description,
            OfferType = OfferTypeEnum.Pro,
            Price = (await _planRepo.GetPlanByIdAsync(product.Metadata.First().Value)).Amount.GetValueOrDefault()
        });
}

如何使用async / await的简单示例: 假设您有使用存储库获取产品列表的服务 - 所有这些服务现在都是同步的:

public class Repository : IRepository
{
    public List<Product> GetProducts()
    {
        return _dbContext.Products.ToList();
    }
}

public class Service : IService
{
    private readonly IRepository _repository;

    public Service(IRepository repository)
    {
        _repository = repository;
    }

    public List<Product> GetProductsFromDb()
    {
        return _repository.GetProducts();
    }
}

现在您要更改此代码以使其异步工作:

public class Repository : IRepository
{
    public async Task<List<Product>> GetProductsAsync()
    {
        return await _dbContext.Products.ToListAsync();
    }
}

public class Service : IService
{
    private readonly IRepository _repository;

    public Service(IRepository repository)
    {
        _repository = repository;
    }

    public async Task<List<Product>> GetProductsFromDbAsync()
    {
        return await _repository.GetProductsAsync();
    }
}