【问题标题】:Console Application - DbContext instance cannot be used inside OnConfiguring控制台应用程序 - DbContext 实例不能在 OnConfiguring 中使用
【发布时间】:2019-03-07 06:45:36
【问题描述】:

我正在使用 Asp.Net Core Console Application 和 Entiy Framework Core 以及 Unit of Work 存储库模式。当我使用多线程函数时,我得到这个错误:

DbContext 实例不能在 OnConfiguring 中使用,因为此时它仍在配置中。如果在前一个操作完成之前对此上下文启动了第二个操作,则可能会发生这种情况。不保证任何实例成员都是线程安全的。

UnitOfwork.cs

public interface IUnitOfWork : IDisposable
{
    void Commit();
    ApplicationDbContext GetContext();
}

public class UnitOfWork : IUnitOfWork
{
    private readonly ApplicationDbContext _applicationDbContext;

    public UnitOfWork(ApplicationDbContext applicationDbContext)
    {
        _applicationDbContext = applicationDbContext;
    }

    public void Commit()
    {
        try
        {
            _applicationDbContext.SaveChanges();
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex);
        }
    }

    public ApplicationDbContext GetContext()
    {
        return _applicationDbContext;
    }

    public void Dispose()
    {
        _applicationDbContext.Dispose();
    }
}

IRepository.cs

public interface IGenericRepository<T>
    where T : class, IEntity
{
    List<T> GetAll(Expression<Func<T, bool>> filter = null,
        Func<IQueryable<T>, IOrderedEnumerable<T>> orderBy = null,
        string includeProperties = "");

    T FindSingle(int id);

    T FindBy(Expression<Func<T, bool>> predicate, string includeProperties = "");

    void Add(T toAdd);

    void Update(T toUpdate);

    void Delete(int id);

    void Delete(T entity);
}

Repository.cs

public class GenericRepository<T> : IGenericRepository<T>
    where T : class, IEntity
{
    private readonly IUnitOfWork _unitOfWork;

    public GenericRepository(IUnitOfWork unitOfWork)
    {
        _unitOfWork = unitOfWork;
    }

    public virtual List<T> GetAll(Expression<Func<T, bool>> filter = null,
        Func<IQueryable<T>, IOrderedEnumerable<T>> orderBy = null,
        string includeProperties = "")
    {
        IQueryable<T> query = _unitOfWork.GetContext().Set<T>();

        if (filter != null)
        {
            query = query.Where(filter);
        }

        foreach (string includeProperty in includeProperties.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
        {
            query = query.Include(includeProperty);
        }

        if (orderBy != null)
        {
            return orderBy(query).ToList();
        }

        return query.ToList();
    }

    public virtual T FindSingle(int id)
    {
        return _unitOfWork.GetContext().Set<T>().Find(id);
    }

    public virtual T FindBy(Expression<Func<T, bool>> predicate, string includeProperties = "")
    {
        IQueryable<T> query = _unitOfWork.GetContext().Set<T>();
        foreach (string includeProperty in includeProperties.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
        {
            query = query.Include(includeProperty);
        }
        return query.Where(predicate).FirstOrDefault();
    }

    public virtual void Add(T toAdd)
    {
        _unitOfWork.GetContext().Set<T>().Add(toAdd);
    }

    public virtual void Update(T toUpdate)
    {
        _unitOfWork.GetContext().Entry(toUpdate).State = EntityState.Modified;
    }

    public virtual void Delete(int id)
    {
        T entity = FindSingle(id);
        _unitOfWork.GetContext().Set<T>().Remove(entity);
    }

    public virtual void Delete(T entity)
    {
        _unitOfWork.GetContext().Set<T>().Remove(entity);
    }
}

商业服务;

public interface IUserService
{
    void CreateUser(UserEntity userEntity, bool commit = false);
}
public class UserService : IUserService
{
    private readonly IGenericRepository<UserEntity> _userRepository;
    private readonly IUnitOfWork _unitOfWork;

    public UserService(IUnitOfWork unitOfWork, IGenericRepository<UserEntity> userRepository)
    {
        _unitOfWork = unitOfWork;
        _userRepository = userRepository;
    }

    public void CreateUser(UserEntity userEntity, bool commit = false)
    {
        try
        {
            _userRepository.Add(userEntity);

            if (commit)
                _unitOfWork.Commit();
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }
}

控制台 Main.cs;

class Program
{
    public static ServiceProvider ServiceProvider;

    static void Main(string[] args)
    {
        InitializeIoc();

        Task.Run(() => { FuncA(); });

        Task.Run(() => { FuncB(); });

        Console.ReadLine();
    }

    private static void InitializeIoc()
    {
        ServiceProvider = new ServiceCollection()
            .AddDbContext<ApplicationDbContext>()
            .AddTransient<IUnitOfWork, UnitOfWork>()
            .AddTransient(typeof(IGenericRepository<>), typeof(GenericRepository<>))
            .AddTransient<IUserService, UserService>()
            .BuildServiceProvider();
    }

    private static void FuncA()
    {
        var userService = ServiceProvider.GetService<IUserService>();
        for (int i = 0; i < 100; i++)
        {
            userService.CreateUser(new UserEntity { FirstName = "FuncA_" + Guid.NewGuid(), LastName = "Last", CreatedDate = DateTime.Now }, false);
        }
    }
    private static void FuncB()
    {
        var userService = ServiceProvider.GetService<IUserService>();
        for (int i = 0; i < 100; i++)
        {
            userService.CreateUser(new UserEntity { FirstName = "FuncB_" + Guid.NewGuid(), LastName = "Last", CreatedDate = DateTime.Now }, false);
        }
    }
}

我该如何解决这个问题?

感谢您的帮助。

【问题讨论】:

  • 嗨 Enes,欢迎来到 Stackoverflow。很高兴看到您正在寻求帮助。但是,为了让任何人都能有效地帮助您,请尝试将代码量减少到允许重现和演示问题所需的最低限度。 current amount of code 使任何人都难以在合理的时间内阅读您的问题(请记住:每个人都在业余时间提供帮助)。在创建MCVE 时阅读此内容。如果出现异常,请始终包含堆栈跟踪。祝你好运。

标签: multithreading dependency-injection .net-core console-application ef-core-2.0


【解决方案1】:

问题是使用的AddDbContext 将您的ApplicationDbContext 注册到ServiceLifetime.Scoped,但您没有创建范围,因此它有效地作为单例工作,因此由多个线程同时共享和访问,这会导致有问题的异常(可能还有很多其他的,因为DbContext 不是线程安全的)。

解决方案是使用范围,例如调用CreateScope 并使用返回的对象ServiceProvider 属性来解析服务:

private static void FuncA()
{
    using (var scope = ServicePropvider.CreateScope())
    {
        var userService = scope.ServiceProvider.GetService<IUserService>();
        // Do something ...
    }
}

private static void FuncB()
{
    using (var scope = ServicePropvider.CreateScope())
    {
        var userService = scope.ServiceProvider.GetService<IUserService>();
        // Do something ...
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-04-29
    • 2018-10-02
    • 1970-01-01
    • 1970-01-01
    • 2019-10-08
    • 1970-01-01
    • 2012-06-23
    相关资源
    最近更新 更多