ASP.NET Core makes it very easy to configure and use Entity Framework Core in web applications. For .NET Core console applications there is no such machinery available but we can still use Entity Framework Core in console applications. This post shows how to wrap database context initialization to separate class and use Entity Framework Core synchronous and asynchronous calls in .NET Core console application.
Preparing project for Entity Framework Core
Before we start writing code we need to make some preparation work. We need configuration file for application as we need some place where we can hold database connection string and maybe some other settings. Settings file should also be available after building or publishing our application. To get done with settings file follow these steps:
- Add appsettings.json file to application root folder.
- Right click on it and select Properties.
- Under Advanced settings set value of Copy to Output Directory to Copy always.
- Click okay.
Now open appsettings.json and add database connection string.
{
"ConnectionStrings": {
"DefaultConnection": "Server=(local);Database=mydb;User ID=user;Password=pass;MultipleActiveResultSets=true"
}
}
When we run application then appsettings.json is copied to Debug or Release folder during build and we don’t have to copy it manually. It contains database connection string and it is ready to use.
Add NuGet packages
We need references to some NuGet packages to use Entity Framework Core and settings from settings file. Here are required NuGet packages:
- Microsoft.EntityFrameworkCore.SqlServer
- Microsoft.Extensions.Configuration
- Microsoft.Extensions.Configuration.Json
With packages in place we are ready to get started with real thing.
Creating database context and entities
To keep things simple I will use simplified version of database context from my ASP.NET/ASP.NET Core paging solution and PressRelease entity.
public class PressRelease
{
public int Id { get; set; }
public string Title { get; set; }
public string Company { get; set; }
public DateTime ReleaseDate { get; set; }
}
public class DotNetPagingDbContext : DbContext
{
public DotNetPagingDbContext(DbContextOptions<DotNetPagingDbContext> options) : base(options)
{
}
public DbSet<PressRelease> PressReleases { get; set; }
}
Now we have database context and one simple entity and it’s time to start using them.
Building database context factory
Before using database context we need options object that carries configuration of it. To keep our code clean we create factory class for our database context options. The factory class reads connection string from application settings, creates options object and returns us already initialized database context.
Update. As reader Qiang pointed out then factory should implement IDesignTimeDbContextFactory so Entity Framework Core migrations can be used too. This one here is primitive implementation and it doesn’t consider design time matters. Still it offers a starting point for your own database context factory.
public class DotNetPagingDbContextFactory : IDesignTimeDbContextFactory<DotNetPagingDbContext>
{
private static string _connectionString;
public DotNetPagingDbContext CreateDbContext()
{
return CreateDbContext(null);
}
public DotNetPagingDbContext CreateDbContext(string[] args)
{
if (string.IsNullOrEmpty(_connectionString))
{
LoadConnectionString();
}
var builder = new DbContextOptionsBuilder<DotNetPagingDbContext>();
builder.UseSqlServer(_connectionString);
return new DotNetPagingDbContext(builder.Options);
}
private static void LoadConnectionString()
{
var builder = new ConfigurationBuilder();
builder.AddJsonFile("appsettings.json", optional: false);
var configuration = builder.Build();
_connectionString = configuration.GetConnectionString("DefaultConnection");
}
}
In real solutions we should throw some exception in LoadConnectionString() method when connection string empty. But anyway we have now factory class that hides details of creating database context.
Using database context in console application
We are ready to use our database context to ask data from database. The code is actually very simple.
class Program
{
static void Main(string[] args)
{
using (var context = new DotNetPagingDbContextFactory.CreateDbContext())
{
var releases = context.PressReleases.Take(5);
foreach(var release in releases)
{
Console.WriteLine(release.Title);
}
}
Console.WriteLine("\r\nPress any key to continue ...");
Console.Read();
}
}
We can also switch our application to use C# 7.1 and use async Main with new asynchronous methods of Entity Framework Core.
class Program
{
static async Task Main(string[] args)
{
using (var context = new DotNetPagingDbContextFactory.CreateDbContext())
{
var releases = await context.PressReleases.Take(5).ToListAsync();
foreach(var release in releases)
{
Console.WriteLine(release.Title);
}
}
Console.WriteLine("\r\nPress any key to continue ...");
Console.Read();
}
}
Now we have also asynchronous version of our application,
Wrapping up
Entity Framework Core can be also used with .NET Core console applications. Although ASP.NET Core provides some better mechanisms for application configuring and also dependency injection we can build simple database context factory and hide some dirty details from other parts of code in our application. It is also possible to have dependency injection in .NET Core console applications but this is the topic of some of my next posts.
View Comments (4)
It will be better if DotNetPagingDbContextFactory implements IDesignTimeDbContextFactory so the ef migration can be used.
Thanks for feedback Qiang. I modified the factory class to implement IDesignTimeDbContextFactory interface.
thanks for your post
minor typo:
new DotNetPagingDbContextFactory.CreateDbContext() => new DotNetPagingDbContextFactory().CreateDbContext()
It's very clear guide, excellent explanation. Good job.