DbContext cannot find database

2019-08-07 18:58发布

The connection string for our app is set in appsettings.json

  "Data": {
"DefaultConnection": {
  "ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=Customers;Trusted_Connection=True;MultipleActiveResultSets=true",

In ConfigureServices we have

            services.AddEntityFramework()
            .AddSqlServer()
            .AddDbContext<CustomersContext>(options =>
                options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]));

This seems to work in cases like this

var membershipUser = await _userManager.FindByEmailAsync(email);

and this

var result = await _userManager.CreateAsync(newUser);

but falls over when I try this

            using (var customers = new CustomersContext())
        {
            var deviceList = customers.Devices.Where(d => d.UserId == membershipUser.Id);

The error is InvalidOperationException: No database providers are configured. Configure a database provider by overriding OnConfiguring in your DbContext class or in the AddDbContext method when setting up services.

If I try this

            public partial class CustomersContext : IdentityDbContext<ApplicationUser>
// note this inherits from IdentityDbContext<ApplicationUser> not DbContext
// refer http://stackoverflow.com/questions/19902756/asp-net-identity-dbcontext-confusion
{
    protected override void OnConfiguring(DbContextOptionsBuilder options)
    {
        options.UseSqlServer(@"Server=(localdb)\\mssqllocaldb;Database=Customers;Trusted_Connection=True;MultipleActiveResultSets=true");
    }

I get this error

Local Database Runtime error occurred. Specified LocalDB instance name is invalid

Why is it my app can find the database in some cases but not others?

1条回答
劫难
2楼-- · 2019-08-07 19:39

The problem is that although you've configured a CustomerContext with the DI services as shown here:

services.AddEntityFramework()
        .AddSqlServer()
        .AddDbContext<CustomersContext>(options =>
           options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]));

You are not having the CustomerContext injected, instead you are newing it up like this:

using (var customers = new CustomersContext())
 {
...
}

using a constructor that takes no parameters, so your CustomersContext is not configured like the one in startup and it has no connection string.

Since you mention you need it in the AccountController, then all you need to do is add CustomersContext to the constructor of AccountController, so that the one you configured in startup will get injected. Like this:

private readonly UserManager<ApplicationUser> _userManager;
private readonly SignInManager<ApplicationUser> _signInManager;
private readonly IEmailSender _emailSender;
private readonly ISmsSender _smsSender;
private readonly ILogger _logger;
private CustomersContext _customerContext;

public AccountController(
    UserManager<ApplicationUser> userManager,
    SignInManager<ApplicationUser> signInManager,
    IEmailSender emailSender,
    ISmsSender smsSender,
    ILoggerFactory loggerFactory,
    CustomersContext customerContext)
{
    _userManager = userManager;
    _signInManager = signInManager;
    _emailSender = emailSender;
    _smsSender = smsSender;
    _logger = loggerFactory.CreateLogger<AccountController>();
    _customerContext = customerContext;
}

That way you get a properly configured CusotmersContext and you don't have to new it up yourself. If for some reason you did want to new it up yourself you need to do so using a constructor that takes IServiceProvider and DbContextOptions. So you would receive those objects in the constructor of AccountController and you would pass them in as you new up the CustomersContext like this:

using (var customers = new CustomersContext(serviceProvider, dbContextOptions))
 {
...
}
查看更多
登录 后发表回答