【问题标题】:A second operation started on this context before a previous operation completed在前一个操作完成之前在此上下文上启动了第二个操作
【发布时间】:2017-05-09 05:00:35
【问题描述】:

我有一个带有 asp.net 核心和实体框架核心的项目,出于性能原因,我使用 MemoryCache。 ForumQueryManager 类用于查询论坛数据。此类数据使用 CacheManager Get 方法并传递缓存键和超时缓存时间以及缓存为空时从数据库中检索数据的方法。此代码几乎总是有效。但有时会抛出异常

例外:

处理请求时发生未处理的异常。 InvalidOperationException:在此上下文中启动了第二个操作 在之前的操作完成之前。任何实例成员都不是 保证是线程安全的。

Microsoft.EntityFrameworkCore.Internal.ConcurrencyDetector.EnterCriticalSection()

论坛查询管理器:

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

    private readonly ICacheManager _cacheManager;

    public ForumQueryManager(ApplicationDbContext 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;
    }
}

缓存管理器:

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;
    }
}

【问题讨论】:

  • 异常清楚地解释了 DbContext 不是线程安全的。每个请求或每个线程解决它。你如何将上下文传递给ForumQueryManager
  • DbContext 是按请求使用此代码 services.AddDbContext(options => options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]));
  • 缓存管理器的生命周期是多久?将其与 EF 匹配。
  • cacheManager 是暂时的

标签: asp.net-core entity-framework-core memorycache


【解决方案1】:

ForumQueryManager 必须是瞬态的,否则_dbContext 变量将被重用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-01
    • 2020-01-22
    • 1970-01-01
    • 2018-11-07
    • 2021-10-22
    • 2020-03-13
    • 2017-03-14
    • 2020-06-05
    相关资源
    最近更新 更多