Entity Framework Core context in separate assembly

By Dawid on (tags: ASP.NET, context, core, ef core, categories: code)

Most of example currently available on the internet shows how’s to start using ASP.NET Core and EF Core implemented in the same assembly. In the RC1 there was couple of tricks which we had to implement if we would like to have separate assembly with data model definition.

In RC2 release it’s a little bit easier. Bellow I’ll show you how you can achieve that.

This is our application context:

   1: public class ApplicationContext : DbContext
   2: {
   3:     ... 
   4:     public DbSet<Project> Projects { get; set; }        
   5:     public DbSet<Employee> Employees { get; set; }
   6:     ...
   7:  
   8:  
   9:     public BackofficeContext(DbContextOptions<ApplicationContext> options)
  10:         : base(options)
  11:     {
  12:     }
  13:  
  14:     protected override void OnModelCreating(ModelBuilder builder)
  15:     {
  16:         //here you can configure your model
  17:         builder.Entity<Project>(project =>
  18:         {
  19:             project.Property(p => p.Name).IsRequired();
  20:         });
  21:     }
  22: }

The most important part here is to pass options to the base class constructor. Thanks to that we can configure connection string and database provider where most of configuration and services are registered in ASP.NET Core – in Startup.cs class.

   1: public class Startup
   2: {
   3:     public Startup(IHostingEnvironment env)
   4:     {
   5:         var builder = new ConfigurationBuilder()
   6:             .SetBasePath(env.ContentRootPath)
   7:             .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
   8:             .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);
   9:  
  10:         builder.AddEnvironmentVariables();
  11:         Configuration = builder.Build();
  12:     }
  13:  
  14:     public IConfigurationRoot Configuration { get; }
  15:  
  16:  
  17:     public void ConfigureServices(IServiceCollection services)
  18:     {
  19:         services.AddEntityFrameworkSqlServer().AddDbContext<ApplicationContext>((serviceProvider, options) =>
  20:         {
  21:             options.UseSqlServer(Configuration["Application:ConnectionString"]).UseInternalServiceProvider(serviceProvider);
  22:         });
  23:  
  24:         services.AddOptions();
  25:  
  26:         ...
  27:  
  28:         services.AddMvc()
  29:             .AddViewLocalization()
  30:             .AddDataAnnotationsLocalization();            
  31:     }
  32:  
  33:     public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
  34:     {
  35:
  36:  
  37:         ConfigureLogging(loggerFactory);
  38:         ConfigureLocalization(app);
  39:  
  40:         if (env.IsDevelopment())
  41:         {
  42:             app.UseBrowserLink();
  43:             app.UseDeveloperExceptionPage();
  44:             app.UseDatabaseErrorPage();
  45:         }
  46:         else
  47:         {
  48:             app.UseExceptionHandler($/Account/Error");
  49:         }
  50:  
  51:         app.UseStaticFiles();
  52:  
  53:         ...
  54:  
  55:         app.UseMvc(routes =>
  56:         {
  57:             routes.MapRoute(name: "default", template: "{controller=Dashboard}/{action=Index}/{id?}");
  58:         });
  59:  
  60:         EnsureDatabase(app);
  61:     }
  62:  
  63:     private void EnsureDatabase(IApplicationBuilder app)
  64:     {
  65:         using (var serviceScope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope())
  66:         {
  67:             serviceScope.ServiceProvider.GetService<BackofficeContext>().Database.EnsureCreated();
  68:             serviceScope.ServiceProvider.GetService<BackofficeContext>().Database.Migrate();
  69:             serviceScope.ServiceProvider.GetService<BackofficeContext>().EnsureSeedData();
  70:         }
  71:     }
  72: }

And that’s all! There is no need to create separate empty Startup class in the assembly with database context or other tricks. Like I show above, you just need to select database provider and provide connection string. Providing external service provider isn’t needed. This UseInternalServiceProvider(serviceProvider) is new in RC2, you can get more information’s about it here.