2017-05-09 6 views
1

성능상의 이유로 asp.net 코어 및 엔터티 프레임 워크 코어가있는 프로젝트가 있습니다. 이는 MemoryCache를 사용합니다. ForumQueryManager 클래스는 포럼 데이터와이 클래스를 사용하여 데이터를 쿼리하는 데 사용됩니다. CacheManager 메서드를 가져 와서 캐시 키와 시간 제한 캐시 시간을 전달하고 데이터베이스에서 데이터를 검색하기 위해 캐시가 비어있는 경우 메서드를 전달합니다. 이 코드는 거의 항상 작동합니다. 때로는 예외를이전 작업이 완료되기 전에이 컨텍스트에서 시작된 두 번째 작업

예외를 발생 : 요청을 처리하는 동안

되지 않은 예외가 발생했습니다. InvalidOperationException : 이전 작업이 완료되기 전에이 컨텍스트에서 시작된 두 번째 작업이 입니다. 모든 인스턴스 구성원은 스레드 안전성이 보장 된 이 아닙니다.

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

예외는 DbContext가 스레드로부터 안전하지 않다는 것을 분명히 설명합니다. 요청 당 또는 스레드별로 해결하십시오. 어떻게 컨텍스트를'ForumQueryManager'에 넘깁니까? –

+0

DbContext는 요청 당이 코드를 사용합니다. services.AddDbContext (options => options.UseSqlServer (Configuration [ "Data : DefaultConnection : ConnectionString"]))); –

+0

캐시 관리자의 수명은 어떻게됩니까? EF와 일치시킵니다. – ssmith

답변

0

ForumQueryManager 그렇지 않으면 _dbContext 변수 것 과도 있어야 재사용.