I found a solution from stackoverflow how to apply migration to a console application with ef core and dependency injection as follows. It works but the method name BuildWebHost seems to be weird for non asp.net core projects.
Here I request a better name for it. Any suggestion is welcome!
```C#
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using System;
namespace Example
{
public class TheContext : DbContext
{
public TheContext(DbContextOptions
public DbSet
}
public class User
{
public int Id { get; set; }
public string Name { get; set; }
}
public class TheApp
{
readonly TheContext _theContext;
public TheApp(TheContext theContext) => _theContext = theContext;
public void Run()
{
// Do something on _theContext
}
}
class Program
{
// this connection string must be retrieved from a secure file.
private static readonly string _connectionString = "Data Source = MyDatabase.db";
private static void ConfigureServices(IServiceCollection isc)
{
isc.AddDbContextPool<TheContext>(options => options.UseSqlite(_connectionString));
isc.AddSingleton<TheApp>();
}
private static UselessWrapper BuildWebHost(string[] args)
{
// create service collection
IServiceCollection isc = new ServiceCollection();
ConfigureServices(isc);
// create service provider
IServiceProvider isp = isc.BuildServiceProvider();
return new UselessWrapper { Services = isp };
}
private static void Main(string[] args)
{
BuildWebHost(args).Services.GetService<TheApp>().Run();
}
private class UselessWrapper
{
public IServiceProvider Services { get; set; }
}
}
}
```
@sadqiang Using IDesignTimeDbContextFactory would be the mode idiomatic way of doing it. However, you should also be careful about the lifetime used to register the context. By default it gets registered as scoped, but the code above doesn't ever create a scope to resolve it. Registering as singleton instead and using the factory looks like this:
```C#
public class TheContext : DbContext
{
public TheContext(DbContextOptions
public DbSet
}
public class User
{
public int Id { get; set; }
public string Name { get; set; }
}
public class TheApp
{
readonly TheContext _theContext;
public TheApp(TheContext theContext) => _theContext = theContext;
public void Run()
{
// Do something on _theContext
}
}
class Program
{
// this connection string must be retrieved from a secure file.
private static readonly string _connectionString = "Data Source = MyDatabase.db";
private static void ConfigureServices(IServiceCollection isc)
{
isc.AddDbContext<TheContext>(
options => options.UseSqlite(_connectionString),
ServiceLifetime.Singleton,
ServiceLifetime.Singleton);
isc.AddSingleton<TheApp>();
}
private static IServiceProvider CreateServiceProvider()
{
// create service collection
IServiceCollection isc = new ServiceCollection();
ConfigureServices(isc);
// create service provider
return isc.BuildServiceProvider();
}
private static void Main(string[] args)
{
CreateServiceProvider().GetService<TheApp>().Run();
}
private class Factory : IDesignTimeDbContextFactory<TheContext>
{
public TheContext CreateDbContext(string[] args)
=> CreateServiceProvider().GetService<TheContext>();
}
}
To keep registering it as scoped requires an appropriate scope to be created to resolve it from:
```C#
public class TheContext : DbContext
{
public TheContext(DbContextOptions<TheContext> options) : base(options) { }
public DbSet<User> Users { get; set; }
}
public class User
{
public int Id { get; set; }
public string Name { get; set; }
}
public class TheApp
{
readonly TheContext _theContext;
public TheApp(TheContext theContext) => _theContext = theContext;
public void Run()
{
// Do something on _theContext
}
}
class Program
{
// this connection string must be retrieved from a secure file.
private static readonly string _connectionString = "Data Source = MyDatabase.db";
private static void ConfigureServices(IServiceCollection isc)
{
isc.AddDbContext<TheContext>(options => options.UseSqlite(_connectionString));
isc.AddSingleton<TheApp>();
}
private static IServiceProvider CreateServiceProvider()
{
// create service collection
IServiceCollection isc = new ServiceCollection();
ConfigureServices(isc);
// create service provider
return isc.BuildServiceProvider();
}
private static void Main(string[] args)
{
using (var scope = CreateServiceProvider().CreateScope())
{
scope.ServiceProvider.GetService<TheApp>().Run();
}
}
private class Factory : IDesignTimeDbContextFactory<TheContext>
{
public TheContext CreateDbContext(string[] args)
=> CreateServiceProvider().CreateScope().ServiceProvider.GetService<TheContext>();
}
}
@ajcvickers I have 2 questions, I hope you can answer
1.why does AddDbContextPool have no overload method for ServiceLifetime parameters?
2.I have a service on the generic host, how to get a brand new DbContext from the DbContextPool on every call.
@Varorbc
@ajcvickers can you provider an orleans with ef core sample?
@ajcvickers:
I am still thinking of your second example in which the default scope of TheContext is used.
TheApp is registered as a singleton, why did you make a scope when resolving TheApp? Is it due to the scoped TheContext that is internally used by TheApp?
private static void Main(string[] args)
{
using (var scope = CreateServiceProvider().CreateScope())
{
scope.ServiceProvider.GetService<TheApp>().Run();
}
}
Most helpful comment
@sadqiang Using options) : base(options) { } Users { get; set; }
IDesignTimeDbContextFactorywould be the mode idiomatic way of doing it. However, you should also be careful about the lifetime used to register the context. By default it gets registered as scoped, but the code above doesn't ever create a scope to resolve it. Registering as singleton instead and using the factory looks like this:```C#
public class TheContext : DbContext
{
public TheContext(DbContextOptions
public DbSet
}
public class User
{
public int Id { get; set; }
public string Name { get; set; }
}
public class TheApp
{
readonly TheContext _theContext;
}
class Program
{
// this connection string must be retrieved from a secure file.
private static readonly string _connectionString = "Data Source = MyDatabase.db";
}