I have a lambda expression with a Select where a new ResourcesResponse.Resource object is created. The Resource object has a calculated Order field which calls an async repository method called GetResourceTypeOrder and everything looks as follows:
ResourcesResponse instantiation:
var tmp = new ResourcesResponse
{
Cost = aux.Sum(s => s.Cost),
Resources = aux
.OrderBy(k => k.Order)
.ThenBy(k => k.TypeId)
.Select(async s => new ResourcesResponse.Resource
{
Id = ((ulong)s.Id).ToString(),
Charge = s.Charge,
Cost = s.Cost,
CurrencyCode = s.CurrencyCode,
ForecastCharge = s.ForecastCharge,
ForecastCost = s.ForecastCost,
ForecastUsedUnits = s.ForecastUsedUnits,
ParentId = ((ulong?)s.ParentId).ToString(),
Order = await _resourcesRepository.GetResourceTypeOrder(s.TypeId),
Rate = s.Rate,
TypeId = s.TypeId,
UsedUnits = s.UsedUnits,
})
.ToArray(),
Id = ((ulong)entry.Id).ToString(),
Name = entry.Name,
Description = entry.Description,
OriginalId = entry.OriginalId,
ResourceTypeId = entry.ResourceTypeId,
ResourceType = await _resourcesRepository.GetResourceTypeName(entry.ResourceTypeId),
Order = await _resourcesRepository.GetResourceTypeOrder(entry.ResourceTypeId),
State = entry.State,
Zone = entry.Zone,
Charge = aux.Sum(s => s.Charge),
};
ResourceResponse:
public class ResourcesResponse
{
public string Id { get; set; } = default!;
public string Name { get; set; } = default!;
public string? Description { get; set; } = default!;
public string OriginalId { get; set; } = default!;
public string ResourceType { get; set; } = default!;
[JsonIgnore]
public int? Order { get; set; } = default!;
public ResourceTypeValues ResourceTypeId { get; set; }
public string? CurrencyCode => Resources?.FirstOrDefault()?.CurrencyCode;
public decimal? Charge { get; set; }
public decimal Cost { get; set; }
public decimal? ForecastCharge { get; set; }
public decimal? ForecastCost { get; set; }
public string Zone { get; set; } = default!;
public string State { get; set; } = default!;
public Resource[] Resources { get; set; } = default!;
public sealed class Resource
{
[JsonIgnore]
public string Id { get; set; } = default!;
[JsonIgnore]
public string? ParentId { get; set; } = default!;
[JsonIgnore]
public int? Order { get; set; } = default!;
public string CurrencyCode { get; set; } = default!;
public decimal Rate { get; set; }
public long UsedUnits { get; set; }
public decimal Cost { get; set; }
public decimal? Charge { get; set; }
public long? ForecastUsedUnits { get; set; }
public decimal? ForecastCost { get; set; }
public decimal? ForecastCharge { get; set; }
public string Type { get; set; } = default!;
public ResourceTypeValues TypeId { get; set; }
public string? Unit { get; set; } = default!;
public bool? Hourly { get; set; } = default!;
}
}
ResourceTypeOrder:
public async Task<int?> GetResourceTypeOrder(ResourceTypeValues resourceTypeId)
{
ICache.Operation<int?> myTableCacheImplementation = async delegate (string key)
{
var dic = await _repositoryResourceTypes.FindAll().ToDictionaryAsync(k => k.Id);
return dic[resourceTypeId].Order;
};
return await _vdcCache.GetOrCreateAsync(ResourceTypeCacheKey.ResourceTypeOrder, myTableCacheImplementation, null);
}
My problem is I don’t know where to put the missing await (or whatever is needed for the entire expression to be accepted by the compiler).
For the parent ResourceResponse there is also a calculated Order field, but as you can see that one is correct.
It is obvious that I could add a .Result to the end of GetResourceTypeOrder and remove the async operator, but that’s not the idea of an async / await.
8
I’ll answer myself:
The way to handle this (taking @Fildor comment as a start point) was to refactor the GetResourceTypeOrder method so it returns the complete dictionary, instead of a particular element. Then I just have to retrieve the dictionary before the ResourcesResponse instance creation and get -and assign- the corresponding Order to “Order” field as resourceTypes[s.TypeId].Order:
var resourceTypes = await _resourcesRepository.GetResourceTypes();
var tmp = new ResourcesResponse
{
Cost = aux.Sum(s => s.Cost),
Resources = aux
.OrderBy(k => k.Order)
.ThenBy(k => k.TypeId)
.Select(s => new ResourcesResponse.Resource
{
Id = ((ulong)s.Id).ToString(),
Charge = s.Charge,
Cost = s.Cost,
CurrencyCode = s.CurrencyCode,
ForecastCharge = s.ForecastCharge,
ForecastCost = s.ForecastCost,
ForecastUsedUnits = s.ForecastUsedUnits,
ParentId = ((ulong?)s.ParentId).ToString(),
Order = resourceTypes[s.TypeId].Order,
Rate = s.Rate,
TypeId = s.TypeId,
UsedUnits = s.UsedUnits,
}).ToArray(),
Id = ((ulong)entry.Id).ToString(),
Name = entry.Name,
Description = entry.Description,
OriginalId = entry.OriginalId,
ResourceTypeId = entry.ResourceTypeId,
ResourceType = await _resourcesRepository.GetResourceTypeName(entry.ResourceTypeId),
Order = await _resourcesRepository.GetResourceTypeOrder(entry.ResourceTypeId),
State = entry.State,
Zone = entry.Zone,
Charge = aux.Sum(s => s.Charge),
};
GetResourceTypes:
public async Task<IReadOnlyDictionary<ResourceTypeValues, ResourceTypes>> GetResourceTypes()
{
ICache.Operation<IReadOnlyDictionary<ResourceTypeValues, ResourceTypes>> myTableCacheImplementation = async delegate (string key)
{
return await _repositoryResourceTypes.FindAll().ToDictionaryAsync(k => k.Id);
};
return await _vdcCache.GetOrCreateAsync(ResourceTypeCacheKey.ResourceTypeOrder, myTableCacheImplementation, null);
}