So, the error is basically what is mentioned in Entity Framework,There is already an open DataReader associated with this Connection which must be closed first - Stack Overflow
In that context, I understand what's going on and the reason for error based on the explanation.
And then I recently encountered the same error after applying best practice suggested by http://www.asyncfixer.com/
The code is a custom localizer that uses SQL Database as it's store instead of resource files. In brief, it provides a string from db if it's not already cached in memory. In addition, if a string is not in db it adds it to db as well.
The code pieces in question are below (2 methods). For the error to happen the 3 changes must be made to both the methods as in comments related to async await syntax
I would like to know a bit about the internals for this exception with these changes
Method 1
public async Task<LocalizedString> GetResourceAsync(string resourceKey, CultureInfo culture, string location = "shared")
{
var tenant = ((MultiTenantContextAccessor<AppTenant>)_serviceProvider.GetRequiredService(typeof(IMultiTenantContextAccessor<AppTenant>))).MultiTenantContext.TenantInfo;
if (string.IsNullOrWhiteSpace(resourceKey))
throw new ArgumentNullException(nameof(resourceKey));
var cacheKey = $"{location}.{resourceKey}";
if (!_cacheProvider.TryGetValue(tenant.Id, cacheKey, culture, out var value))
{
using (var scope = _serviceProvider.GetScopedService(out T context))
{
var item = context
.Set<LocalizationResource>()
.SelectMany(r => r.Translations)
.Where(t => t.Resource.ResourceKey == resourceKey
&& t.Resource.Module == location
&& t.Language == culture.Name)
.Select(p => new
{
p.LocalizedValue
})
.SingleOrDefault();
//change 1) change above to use **await context** {...} **SingleOrDefaultAsync()**
if (item == null)
if (_settings.CreateMissingTranslationsIfNotFound)
await AddMissingResourceKeysAsync(resourceKey, location); //AddMissingResourceKeys(resourceKey);
value = item?.LocalizedValue ?? string.Empty;
if (string.IsNullOrWhiteSpace(value))
switch (_settings.FallBackBehavior)
{
case FallBackBehaviorEnum.KeyName:
value = resourceKey;
break;
case FallBackBehaviorEnum.DefaultCulture:
if (culture.Name != DefaultCulture.Name)
return await GetResourceAsync(resourceKey, DefaultCulture,location);
break;
}
}
_cacheProvider.Set(tenant.Id, cacheKey, culture, value);
}
return new LocalizedString(resourceKey, value!);
}
Method 2
private async Task AddMissingResourceKeysAsync(string resourceKey, string location="shared")
////Change 2): remove async from method signature to
////private Task AddMissingResourceKeysAsync(string resourceKey, string location="shared")
{
var modificationDate = DateTime.UtcNow;
//resourceKey = $"{location}.{resourceKey}";
using var scope = _serviceProvider.GetScopedService(out T context);
var resource = context
.Set<LocalizationResource>()
.Include(t => t.Translations)
.SingleOrDefault(r => r.ResourceKey == resourceKey && r.Module==location);
if (resource == null)
{
resource = new LocalizationResource
{
Module = location,
ResourceKey = resourceKey,
//Modified = modificationDate,
Translations = new List<LocalizationResourceTranslation>()
};
context.Add(resource);
}
_requestLocalizationSettings.SupportedCultures.ToList()
.ForEach(culture =>
{
if (resource.Translations.All(t => t.Language != culture.Name))
{
//resource.Modified = modificationDate;
resource.Translations.Add(new LocalizationResourceTranslation
{
Language = culture.Name
//, Modified = modificationDate
});
}
});
await context.SaveChangesAsync();
////change 3) change above to return context.SaveChangesAsync();
}
Once above 3 changes are done it consistently throws this exception and if I remove these changes it works fine.. I would like to know what may be happening behind the scenes for this exception to happen