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();
}
}
}
DB Table:
Advice would be much appreciated.
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.
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.
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.
Related
If we want access to HttpContext in a class library we can simple pass it like this:
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using WebAppLib;
namespace WebApplication
{
public class WebAppMiddleware
{
private readonly RequestDelegate _next;
public WebAppMiddleware(RequestDelegate next)
{
_next = next;
}
public Task Invoke(HttpContext httpContext)
{
Test test = new test();
test.TestMethod(httpContext) <--- passing the current httpcontext to the method.
// Return httpcontext
return _next(httpContext);
}
}
// Extension method used to add the middleware to the HTTP request pipeline.
public static class WebAppMiddlewareExtensions
{
public static IApplicationBuilder UseWebAppMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<WebAppMiddleware>();
}
}
}
My Class library dll file(with FrameworkReference Include="Microsoft.AspNetCore.App" in csproj file)
using Microsoft.AspNetCore.Http;
namespace WebAppLib
{
public class Test
{
public void TestMethod(HttpContext httpContext)
{
httpContext.Response.WriteAsync("hello from haldner");
// continue with context instance
}
}
}
I'm wondering if there's other ways this can be done? Basically I want to avoid passing "httpContext" to my method that i run in my custom middlewear.
Could you please tell me how you want to use this WebAppLib? Will you inject this class into the startup.cs?
If you will inject, then you could use other service inside the asp.net application. Like httpcontextaccessor or else to achieve your requirement. If you don't inject it and you don't want to pass httpcontext into it, you couldn't get it.
Details about how to use it, like this:
inject:
services.AddScoped<IMyDependency, MyDependency>();
services.AddHttpContextAccessor();
MyDependency class:
public class MyDependency : IMyDependency
{
private IHttpContextAccessor _context;
public MyDependency(IHttpContextAccessor context) {
_context = context;
}
public void WriteMessage(string message)
{
var path= _context.HttpContext.Request.Path;
Console.WriteLine($"MyDependency.WriteMessage Message: {message}");
}
}
I will apologize in advance that I am a complete novice with .NET so please bear with me. My goal is to simply be able to pass variables from my Program class to a controller in my setup.
Program.cs
using System;
using System.Collections.Generic;
using System.IO;
namespace EJ2FileManagerService
{
public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Run();
}
public static IWebHost CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((hostingContext, config) =>
{
var test = "results";
})
.UseStartup<Startup>()
.Build();
}
}
I want to be able to consume the variable test in my TestController class. It is located under Controllers/TestController.cs.
TestController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
namespace EJ2FileManagerServices.Controllers
{
[Route("api/[controller]")]
public class TestController : Controller
{
// WANT TO READ TEST VARIABLE HERE
// GET api/values
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET api/values/5
[HttpGet("{id}")]
public string Get(int id)
{
return "value";
}
}
}
This was simply just user error -- the first comment was correct I just needed to do my calls and actions inside the controller versus inside of Program.cs.
Thanks!
I'm trying to create a context for my redis database without using Entity Framework. My connection depends on a ConnectionMultiplexer class, so for unit testing I'm trying to use dependency injection. I'm not sure how to create the using statement for my context without the ConnectionMultiplexer parameter.
Am I doing dependency injection wrong? How can I restructure so I can use the "using" context correctly and have it resolve the dependency for me?
GameSession.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using StackExchange.Redis;
namespace Bored.GameService.GameSession
{
public class GameSessionContext : IGameSession, IDisposable
{
private IDatabase conn;
private readonly IConnectionMultiplexer _muxer;
public GameSessionContext(IConnectionMultiplexer muxer)
{
_muxer = muxer;
string connectionString = Startup.Configuration.GetConnectionString("redis");
_muxer = ConnectionMultiplexer.Connect(connectionString);
//conn = muxer.GetDatabase();
//conn.StringSet("foo", "bar");
//var value = conn.StringGet("foo");
//Console.WriteLine(value);
}
public void GetGameState()
{
throw new NotImplementedException();
}
public void AddGameState()
{
throw new NotImplementedException();
}
public void Dispose()
{
_muxer.Dispose();
}
}
}
Here is where I'm registering the dependency in my startup.cs
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IConnectionMultiplexer, ConnectionMultiplexer>();
services.AddSignalR();
services.AddCors(options =>
{
options.AddPolicy("ClientPermission", policy =>
{
policy.AllowAnyHeader()
.AllowAnyMethod()
.WithOrigins("http://localhost:3000")
.AllowCredentials();
});
});
}
Here is how I'm using it in my GameServiceAPI class:
using Bored.GameService.Clients;
using Bored.GameService.GameSession;
using Bored.GameService.Models;
using Microsoft.AspNetCore.SignalR;
using System.Threading.Tasks;
namespace Bored.GameService.GameServiceAPI
{
public class GameServiceHub : Hub<IGameClient>
{
public Task SendMessage(GameMessage message)
{
// Throws an error because GameSessionContext has no IConnectionMultiplexer parameter passed in.
using (var context = new GameSessionContext())
{
// var gameState = context.GetGameState(context);
// context.AddGameState(gameState);
// Clients.All.ReceiveMessage(gameState);
}
return Clients.All.ReceiveMessage(message);
}
}
}
Thanks to #DavidBrowne's suggestion for registering both the GameServiceHub and GameSessionContext with DI.
Here's the code I used to get this to work:
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IConnectionMultiplexer>(ConnectionMultiplexer.Connect(Configuration.GetConnectionString("redis")));
services.AddScoped<IGameSessionContext, GameSessionContext>();
services.AddSignalR();
services.AddCors(options =>
{
options.AddPolicy("ClientPermission", policy =>
{
policy.AllowAnyHeader()
.AllowAnyMethod()
.WithOrigins("http://localhost:3000")
.AllowCredentials();
});
});
GameSessionContext.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using StackExchange.Redis;
namespace Bored.GameService.GameSession
{
public class GameSessionContext : IGameSessionContext
{
private IDatabase conn;
private readonly IConnectionMultiplexer _muxer;
public GameSessionContext(IConnectionMultiplexer muxer)
{
_muxer = muxer;
}
public string GetGameState()
{
conn = _muxer.GetDatabase();
conn.StringSet("foo", "Here's game state");
return conn.StringGet("foo");
}
public void AddGameState()
{
throw new NotImplementedException();
}
}
}
GameServiceHub.cs
using Bored.GameService.Clients;
using Bored.GameService.GameSession;
using Bored.GameService.Models;
using Microsoft.AspNetCore.SignalR;
using System;
using System.Threading.Tasks;
namespace Bored.GameService.GameServiceAPI
{
public class GameServiceHub : Hub<IGameClient>
{
private IGameSessionContext _context;
public GameServiceHub(IGameSessionContext context)
{
_context = context;
}
public Task SendMessage(GameMessage message)
{
var state = _context.GetGameState();
Console.WriteLine(state);
// var gameState = context.GetGameState(context);
// context.AddGameState(gameState);
return Clients.All.ReceiveMessage(message);
}
}
}
build a web api using entityframeworkcore 2.03 .net core
keep getting the following error tried everything i can think of to get past it not sure what the issue is has anyone else had this iasue ?
InvalidOperationException: No database provider has been configured
for this DbContext. A provider can be configured by overriding the
DbContext.OnConfiguring method or by using AddDbContext on the
application service provider. If AddDbContext is used, then also
ensure that your DbContext type accepts a DbContextOptions
object in its constructor and passes it to the base constructor for
DbContext
startup.cs
using churchy.Repository;
using churchy.Service;
using churchy.Service.Abstractions;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace churchy
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Database connection
services.AddDbContext<ChurchContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("ChurchConnection")));
// Repositories
services.AddScoped<IRepository, Repository.Repository>();
services.AddScoped<IRepositoryFactory, RepositoryFactory>();
// Services
services.AddScoped<IChurchService, ChurchService>();
services.AddMvc();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMvc();
}
}
}
churchcontext.cs
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.EntityFrameworkCore;
using churchy.Model;
namespace churchy.Repository
{
public class ChurchContext: DbContext
{
public ChurchContext()
{
}
public ChurchContext(DbContextOptions<ChurchContext> options) : base(options)
{
}
public DbSet<Church> Churches { get; set; }
public DbSet<Location> Locations { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Church>().ToTable("Church");
}
}
}
Repository.cs
using Microsoft.EntityFrameworkCore;
using System.Linq;
using System.Threading.Tasks;
namespace churchy.Repository
{
public class Repository : IRepository
{
private readonly ChurchContext _context;
public Repository()
{
_context = new ChurchContext();
}
public IQueryable<T> GetAll<T>() where T : class
{
return _context.Set<T>();
}
public Task Create<T>(T entity) where T : class
{
throw new System.NotImplementedException();
}
public Task Delete<T>(int id) where T : class
{
throw new System.NotImplementedException();
}
public Task Update<T>(int id, T entity) where T : class
{
throw new System.NotImplementedException();
}
public void Dispose()
{
_context?.Dispose();
}
}
}
IRepository.cs
using System;
using System.Linq;
using System.Threading.Tasks;
namespace churchy.Repository
{
public interface IRepository : IDisposable
{
IQueryable<T> GetAll<T>() where T : class;
Task Create<T>(T entity) where T :class;
Task Update<T>(int id, T entity) where T : class;
Task Delete<T>(int id) where T : class;
}
}
ChurchController
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using churchy.Service.Abstractions;
namespace churchy.Controllers
{
[Route("api/church")]
public class ChurchController : Controller
{
private readonly IChurchService _churchService;
public ChurchController(IChurchService churchService)
{
_churchService = churchService;
}
// GET: api/<controller>
[HttpGet]
public IActionResult GetAllAsync()
{
var response = _churchService.getChurches();
return Ok(response);
}
// GET api/<controller>/5
[HttpGet("{id}")]
public string Get(int id)
{
return "value3";
}
// POST api/<controller>
[HttpPost]
public void Post([FromBody]string value)
{
}
// PUT api/<controller>/5
[HttpPut("{id}")]
public void Put(int id, [FromBody]string value)
{
}
// DELETE api/<controller>/5
[HttpDelete("{id}")]
public void Delete(int id)
{
}
}
}
Here is your most fundamental problem:
public Repository()
{
_context = new ChurchContext();
}
That's the opposite of Dependency Injection. That context you are manually creating has not been configured.
Quick answer:
public Repository(ChurchContext context)
{
_context = context;
}
Furthermore:
You should get familiar with Dependency Injection in ASP.NET Core: Dependency Injection in ASP.NET Core.
You may want to read this answer of mine for some viewpoints regarding UoW and Repository patterns in ASP.NET Core.
I'm trying to inject a couple of classes in a controller, but I'm failing.
This is what I've done:
Added Ninject.Web.WebApi.WebHost and WebActivatorEx NuGet packages
Created the following class under App_Start:
NinjectWebCommon.cs
using Microsoft.Web.Infrastructure.DynamicModuleHelper;
using Ninject;
using Ninject.Web.Common;
using Ninject.Web.Common.WebHost;
using MyProject;
using MyProject.Models;
using MyProject.Classes;
using System;
using System.Web;
[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(NinjectWebCommon), "Start")]
[assembly: WebActivatorEx.ApplicationShutdownMethodAttribute(typeof(NinjectWebCommon), "Stop")]
namespace MyProject
{
public static class NinjectWebCommon
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
bootstrapper.Initialize(CreateKernel);
}
public static void Stop()
{
bootstrapper.ShutDown();
}
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
RegisterServices(kernel);
return kernel;
}
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IMyContext>().ToSelf().InRequestScope();
kernel.Bind<IErp>().ToSelf().InRequestScope();
}
}
}
Created my classes:
MyContext.cs:
using MyProject.Models;
using System;
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration.Conventions;
using System.Threading.Tasks;
namespace MyProject.Models
{
public interface IMyContext : IDisposable
{
DbSet<Operator> Operators { get; set; }
Task<int> SaveChangesAsync();
}
public class MyContext : DbContext, IMyContext
{
public MyContext () : base("MyContext ") { }
public DbSet<Operator> Operators { get; set; }
public async override Task<int> SaveChangesAsync()
{
return await SaveChangesAsync(CancellationToken.None);
}
}
}
Erp.cs
public interface IErp
{
Task ImportListAsync();
}
public class Erp : IErp
{
private readonly IMyContext _context;
public Erp(IMyContext context)
{
_context = context;
}
public async Task ImportListAsync()
{
// do something
}
}
Created a Controller
using MyProject.Classes;
using MyProject.Models;
using System.Data.Entity;
using System.Threading.Tasks;
using System.Web.Mvc;
namespace MyProject.Controllers
{
public class OperatorsController : Controller
{
private readonly IMyContext _context;
private readonly IErp _erp;
public OperatorsController(IMyContext context, Erp Ierp)
{
_context = context;
_erp = erp;
}
// GET: Operators
public async Task<ActionResult> Index()
{
return View(await _context.Operators.ToListAsync());
}
// GET: Operators/Import
public async Task<ActionResult> Import()
{
await _erp.ImportListAsync();
return View("Index", await _context.Operators.ToListAsync());
}
}
}
But when I run the application I still get the infamous error about the missing of parameterless constructor. This says to me that DI is not working.
I believe your registration calls in RegisterServices are wrong - you cannot bind an interface .ToSelf() - you need to bind the interface to the concrete class that implements it - something like this:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IMyContext>().To<MyContext>().InRequestScope();
kernel.Bind<IErp>().To<Erp>().InRequestScope();
}
With this, you tell the DI container to instantiate an MyContext class whenever in your code you're expecting an IMyContext dependency