skip to Main Content

I need a live demo for a product. Said product uses ASP.NET with Entity Framework.

Currently I create a new in-memory database like this:

var sqliteConnection = new SqliteConnection("DataSource=:memory:");
sqliteConnection.Open();

builder.Services
       .AddDbContextFactory<DatabaseContext>
           (options => options.UseSqlite(sqliteConnection,
                                         o => o.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery)));

However, I need this DbContext to be created for each session ("scoped"), so the live demo of our product always starts with the exact same data, for each session and they do not interfere with each other.

2

Answers


  1. When using dependency injection in dotnet you have three lifetimes available for your services:

    Transient: Services are created each time they’re requested from the service container.

    Singleton: Each request of the service implementation from the dependency injection container uses the same instance.

    Scoped: For web applications, a scoped lifetime indicates that services are created once per client request (connection).

    Detailed Microsoft docs on DI for dotnet here.

    It’s important to note that EF uses a scoped lifetime by default.
    You can modify this behavior by overloading the AddDbContext call.

    Regarding your question: the scoped lifetime is tied to a single web request, not a user session. Also, if you managed to somehow create a new instance of your DbContext with clean information, each new session would be creating a copy of the whole database in memory, which would very quickly become unmanageable.

    Without knowing more about your application, a simple solution would be to tie the user’s sessionId to a new column in each of your tables and use that as a discriminator when serving and modifying data.

    That is, when a user opens the application, a new copy of your data is created with {userSession} added to a column in each of your entities. From that moment onwards, any request to the application will only touch the data assigned to that specific session.

    This will make your DB grow quite quickly, but seeing as your working with an In-Memory DB, any time your AppService/Function is restarted you’ll only be left with the original copy of the data as the DB is created.

    You can also look into a more robust multi-tenancy implementation as documented here.

    Login or Signup to reply.
  2. Hoping that this is just for testing purposes, you can do something as follows:

    I overridden OnConfiguring of DataContext, so every time a new DataContext is created it will connect to a different database name in memory using Guid as name.

    var serviceCollection = new ServiceCollection();
    serviceCollection.AddDbContext<DataContext>();
    var serviceProvider = serviceCollection.BuildServiceProvider();
    
    using (var scope1 = serviceProvider.CreateScope())
    {
        var dbContext = scope1.ServiceProvider.GetRequiredService<DataContext>();
        dbContext.Users.Add(new User { Name = "John" });
        dbContext.SaveChanges();
        Console.WriteLine("User names from scope 1: ");
        Console.WriteLine(string.Join(", ", dbContext.Users.Select(x => x.Name))); 
    }
    
    using (var scope2 = serviceProvider.CreateScope())
    {
        var dbContext = scope2.ServiceProvider.GetRequiredService<DataContext>();
        Console.WriteLine("User names from scope 2: ");
        Console.WriteLine(string.Join(", ", dbContext.Users.Select(x => x.Name)));
    }
    
    
    public class DataContext : DbContext
    {
        public DbSet<User> Users { get; set; }
    
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseInMemoryDatabase(Guid.NewGuid().ToString());
            base.OnConfiguring(optionsBuilder);
        }
    }
    
    public class User
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search