0

I have seen many posts talking about the problem but none of them fixed my problem

the scenario DB Layer with API Controllers IDataRepository DataManagers

Code

Startup.cs

  public void ConfigureServices(IServiceCollection services)
    {
        // Add framework services.
        services.AddDbContext<ApplicationContext>(opts => opts.UseSqlServer(Configuration["ConnectionString:LawyerApplicationDB"]), ServiceLifetime.Transient);
        services.AddSingleton(typeof(IDataRepository<Clients, long>), typeof(ClientManager));
        services.AddSingleton(typeof(IDataRepository<Nationality, long>), typeof(NationalityManager));
        services.AddMvc();
    }

ApplicationContext

public class ApplicationContext: DbContext
{
    public ApplicationContext(DbContextOptions opts) : base(opts)
    {
    }
    
    public DbSet<Clients> Clients { get; set; }
    public DbSet<Nationality> Nationalities { get; set; }
  
    
    
}

The Manager where the error Appear

 public class NationalityManager : IDataRepository<Nationality, long>
{
    private ApplicationContext ctx; //not static

    public NationalityManager(ApplicationContext c)
    {
        ctx = c;
    }
    
    public Nationality Get(long id)
    {

        var nationality = ctx.Nationalities.FirstOrDefault(b => b.Id == id);
        return nationality;
    }

    public IEnumerable<Nationality> GetAll()
    {
        var nationalities = ctx.Nationalities.ToList();
        return nationalities;
    }

the error appear first time and the grid does not show data if i refresh the page the data will show

what i do wrong

this is the tutorial i used Building An ASP.NET Core Application With Web API And Code First Development

Thank you for your help

Community
  • 1
  • 1
Maher Khalil
  • 529
  • 1
  • 15
  • 28
  • In general what you're doing is a very bad pattern. The context is *supposed* to be scoped. By making it transient and then injecting it into a singleton, you're effectively making it singleton as well, accept that each of your repos will have their very own copy of it. That's going to wreck all sorts of havoc, as they cannot coordinate their behavior across the same context instance. Leave the context scoped and make your repos scoped as well. There's no reason for them to be singletons in the first place. – Chris Pratt Mar 06 '19 at 15:18
  • Can you add OnConfiguring method your ApplicationContext class? Put a breakpoint top of it and NationalityManager.Get method. See which one hits first. – ibrahimozgon Mar 06 '19 at 16:45
  • @ibrahimozgon Manager Hit first then override OnConfiguring – Maher Khalil Mar 06 '19 at 17:56
  • @ Chris Pratt i'm new to Core so if you send a better pattern i will change my app is just starting – Maher Khalil Mar 06 '19 at 17:57

1 Answers1

0

You've fallen into a classic situation where you are keeping the context around too long.

Because NationalityManager is registered as a singleton it doesn't matter that your context was registered as transient. Something with a short lifetime injected into something with a long lifetime effectively means the short lifetime is extended by the lifetime of the longer lived thing.

You can either make your manager object shorter lived or you can inject a context factory into your manager. The context factory ensures your (what should be short lived) context is created when its needed.

When you have API calls coming in at the same time, they are attempting to use the non-thread safe context simultaneously. The first call is setting up the model, and then here comes another call wanting to use the model while its being setup.

Prior to EF Core, I've addressed this issue with the original EF designed for .NET Framework. It might give you some more background.

Kit
  • 20,354
  • 4
  • 60
  • 103
  • thank you i came across this link in your post https://github.com/vany0114/EF.DbContextFactory i just wondering how he get data to the controller and view (i can't find views in the post) – Maher Khalil Mar 07 '19 at 07:17