Reputation: 3875
I wrote a method that should get some information from a web service. I wanna avoid extra calls to the service, so I'm trying to put the information in the MemoryCache according to this post.
The difference is that I don't have "SomeHeavyAndExpensiveCalculation" at client, but I delegate the work to web service. So I want to await the call.
As I understand with current implementation I could have multiple requests to the web server, because I cannot await the request inside the lock and that's why it's moved out of the lock.
Is there a better solution?
Thanks.
private static readonly object CompanyInfoLock = new object();
public async Task<CompanyDto> GetCompanyInfo()
{
const string cacheKey = "_COMPANYINFO_";
CompanyDto companyInfo = MemoryCache.Default[cacheKey] as CompanyDto;
if (companyInfo != null) return companyInfo;
CompanyDto company = await _userManagementService.InvokeAsync(x => x.GetCompanyAsync(AppPrincipal.Current.CurrentCompanyId));
lock (CompanyInfoLock)
{
companyInfo = MemoryCache.Default[cacheKey] as CompanyDto;
if (companyInfo != null) return companyInfo;
MemoryCache.Default.Add(cacheKey, company, new CacheItemPolicy
{
SlidingExpiration = new TimeSpan(2, 0, 0)
});
}
return company;
}
Upvotes: 1
Views: 1069
Reputation: 127603
Use a SemaphoreSlim
so you can lock asynchronously and put the lock block before you make the call to the web service.
private static readonly SemaphoreSlim CompanyInfoLock = new SemaphoreSlim (1);
public async Task<CompanyDto> GetCompanyInfo()
{
const string cacheKey = "_COMPANYINFO_";
CompanyDto companyInfo;
companyInfo = MemoryCache.Default[cacheKey] as CompanyDto;
if (companyInfo != null) return companyInfo;
await CompanyInfoLock.WaitAsync();
try
{
//Check a 2nd time inside the lock to see if the cache has the data.
companyInfo = MemoryCache.Default[cacheKey] as CompanyDto;
if (companyInfo != null) return companyInfo;
companyInfo = await _userManagementService.InvokeAsync(x => x.GetCompanyAsync(AppPrincipal.Current.CurrentCompanyId));
MemoryCache.Default.Add(cacheKey, companyInfo, new CacheItemPolicy
{
SlidingExpiration = new TimeSpan(2, 0, 0)
});
return companyInfo;
}
finally
{
CompanyInfoLock.Release();
}
}
Upvotes: 6