2017-05-09 2 views
1

J'ai un projet avec le coeur de framework core et entity asp.net, pour des raisons de performance, j'utilise MemoryCache. La classe ForumQueryManager permet d'interroger les données de forum et cette classe pour l'utilisation des données. CacheManager Méthode get et passe cachekey et timeout du cache et une méthode pour quand le cache est vide pour récupérer des données de la base de données. ce code fonctionne presque toujours. mais parfois jeter exceptionUne deuxième opération a démarré sur ce contexte avant la fin d'une opération précédente

Exception:

Une exception non gérée est survenue lors du traitement de la demande. InvalidOperationException: Une deuxième opération a démarré sur ce contexte avant la fin d'une opération précédente. Tous les membres d'instance ne sont pas garanti être thread-safe.

Microsoft.EntityFrameworkCore.Internal.ConcurrencyDetector.EnterCriticalSection()

ForumQueryManager:

public class ForumQueryManager : IForumQueryManager 
{ 
    private readonly NashrNegarDbContext _dbContext; 
    private readonly ICalender _calender; 

    private readonly ICacheManager _cacheManager; 

    public ForumQueryManager(NashrNegarDbContext dbContext, ICacheManager cacheManager) 
    { 
     _dbContext = dbContext; 
     _cacheManager = cacheManager; 
    } 

    public async Task<List<ForumCategoryDto>> GetAll() 
    { 
     var items = await _cacheManager.Get(CacheConstants.ForumCategories, 20, GetForumCategories); 

     return items; 
    } 

    private async Task<List<ForumCategoryDto>> GetForumCategories() 
    { 
     var categories = await _dbContext.ForumCategories 
      .Select(e => new ForumCategoryDto 
      { 
       Name = e.Name, 
       ForumCategoryId = e.ForumCategoryId 
      }).ToListAsync(); 

     return categories; 
    } 
} 

CacheManager:

public class CacheManager: ICacheManager 
{ 
    private readonly IMemoryCache _cache; 
    private readonly CacheSetting _cacheSetting; 

    public CacheManager(IMemoryCache cache, IOptions<CacheSetting> cacheOption) 
    { 
     _cache = cache; 
     _cacheSetting = cacheOption.Value; 
    } 

    public async Task<List<T>> Get<T>(string cacheKey, int expirationMinutes, Func<Task<List<T>>> function) 
    { 
     List<T> items; 

     if (_cacheSetting.MemeoryEnabled) 
     { 
      var value = _cache.Get<string>(cacheKey); 

      if (value == null) 
      { 
       items = await function(); 

       value = JsonConvert.SerializeObject(items, Formatting.Indented, 
        new JsonSerializerSettings 
        { 
         NullValueHandling = NullValueHandling.Ignore, 
         MissingMemberHandling = MissingMemberHandling.Ignore, 
         ReferenceLoopHandling = ReferenceLoopHandling.Ignore 
        }); 

       _cache.Set(cacheKey, value, 
        new MemoryCacheEntryOptions().SetAbsoluteExpiration(TimeSpan.FromMinutes(expirationMinutes))); 
      } 
      else 
      { 
       items = JsonConvert.DeserializeObject<List<T>>(value); 
      } 

     } 
     else 
     { 
      items = await function(); 
     } 

     return items; 
    } 
} 
+0

L'exception explique clairement que DbContext n'est pas thread-safe. Résolvez-le par requête ou par thread. Comment passez-vous le contexte à 'ForumQueryManager'? –

+0

DbContext est par requête avec ce code services.AddDbContext (options => options.UseSqlServer (Configuration ["Données: DefaultConnection: ConnectionString"])); –

+0

Quelle est la durée de vie du gestionnaire de cache? Correspond à EF. – ssmith

Répondre

0

ForumQueryManager doit être transitoire, sinon la variable _dbContext sera réutilisé.