Reputation: 661
Trying to learn EF Core, have just finished a course online and I am trying to get an integer added to a DB table. .Net 5.0.
I am getting an error when I build the application:
'AddDbContext' was called with configuration, but the context type 'ApplicationDbContext' only declares a parameterless constructor. This means that the configuration passed to 'AddDbContext' will never be used. If configuration is passed to 'AddDbContext', then 'ApplicationDbContext' should declare a constructor that accepts a DbContextOptions and must pass it to the base constructor for DbContext. Microsoft.Extensions.DependencyInjection.EntityFrameworkServiceCollectionExtensions.CheckContextConstructors()
I understand the problem is between ApplicationDBContext.cs and Startup.cs, one has parameters and one is parameterless, but I don't know how to fix it. Other answers online seem to be along the lines of "This is obvious, just fix it" which is not very helpful.
ApplicationDBContext
If I un-comment the empty ApplicationDbContext
functions I no longer get the error, but when I run the program nothing is added to my DB.
using System;
using System.Collections.Generic;
using System.Text;
using MyApp.Areas.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
namespace MyApp.Data
{
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public DbSet<RGWAction> RGWActions { get; set; }
DBConnectionStringFactory GetDBConnectionString = new DBConnectionStringFactory();
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
string ConnectionString = GetDBConnectionString.DBConnectionString();
optionsBuilder.UseSqlServer(ConnectionString).LogTo(Console.WriteLine, new[] { DbLoggerCategory.Database.Command.Name },LogLevel.Information)
.EnableSensitiveDataLogging(); //add to be able to see parameters in your log
}
/*
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
{
}
public ApplicationDbContext()
{
}
*/
}
}
Startup.cs
public void ConfigureServices(IServiceCollection services)
method
services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
RGWAction.cs
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Threading.Tasks;
namespace MyApp.Areas.Identity
{
public class RGWAction
{
public int Id { get; set; }
public string Email { get; set; }
public int Total { get; set; }
public int ReduceMeat { get; set; }
}
}
Program.cs
Just trying to add an integer to the DB on startup right now, to get it working as a learning exercise. My next step will be to trigger it from a UI button.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using MyApp.Data;
using MyApp.Areas.Identity;
namespace MyApp
{
public class Program
{
private static ApplicationDbContext _context = new ApplicationDbContext();
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
InsertNewInteger();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
private static void InsertNewInteger()
{
_context.RGWActions.Add(new RGWAction { ReduceMeat = 1 });
_context.SaveChanges();
}
}
}
Advice would be much appreciated.
Upvotes: 0
Views: 1961
Reputation: 136
Your controller:
public class YourController : Controller
{
[HttpPost] // because data is updated
public async Task<ActionResult> NewIntAction(
[FromServices]
INewIntService newIntService)
{
await newIntService.InsertNewInteger();
....
return View(); // You will need a view NewIntAction in the folder Views/Your
}
}
INewIntService interface :
public interface INewIntService
{
Task InsertNewInteger();
}
NewIntService class:
public sealed class NewIntService : INewIntService
{
public NewIntService(ApplicationDbContext context)
{
_context = context;
}
ApplicationDbContext _context;
public async Task InsertNewInteger()
{
_context.RGWActions.Add(new RGWAction { ReduceMeat = 1 });
await _context.SaveChangesAsync();
}
}
Startup.cs:
services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddTransient<INewIntService, NewIntService>();
Main program:
namespace MyApp
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
InsertNewInteger();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}
I need define no constructor of ApplicationDbContext because the instance of ApplicationDbContext is created by the infrastructure and injected as a dependency into the NewIntService constructor in its context parameter.
Upvotes: 1
Reputation: 136
You need an ApplicationDbContext constructor with a DbContextOptions parameter to insert option dependencies.
You need a default constructor without parameters because you call it explicitly in the _context field initializer. Try to omit this initialization, it is unnecessary if DI works well.
Upvotes: 1
Reputation: 661
Ahhhh, finally! :)
ApplicationDBContext needs all three methods. Does anyone know why?
OnConfiguring(DbContextOptionsBuilder optionsBuilder)
ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
ApplicationDbContext()
Also Program.cs was the wrong place for my InsertNewInteger()
method. It needed to be in the controller for the page load, in this case index.cs
controller.
Upvotes: 0