Error saying.No database provider has been configured for this DbContext - c#

I am facing an error while accesing data from database table saying 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<TContext> object in its constructor and passes it to the base constructor for DbContext.
I have used generic repository pattern. I have my DbContext i.e BlazorContext and model class in seperate class library project.
Any help will be grate.
Below is my connection string in appsettings.json
"ConnectionStrings": {
"myconn": "server=DESKTOP-VM2VP34; database=BlazorDB;Trusted_Connection=True;"
},<br><br>
Below is my startup.cs
services.AddDbContext<BlazorContext>(item => item.UseSqlServer(Configuration.GetConnectionString("myconn")));
Below is my DbContext i.e BlazorContext
namespace Blazor.Model.Models
{
public class BlazorContext:DbContext
{
public BlazorContext()
{
}
public BlazorContext(DbContextOptions<BlazorContext> options)
: base(options)
{
Database.EnsureCreated();
}
public DbSet<Person> Persons { get; set; }
}
}
Below is my generic repository implementation where it show error
namespace Blazor.Repository.Implementation
{
public class GenericRepository<T> : IGenericRepository<T> where T : class
{
protected BlazorContext _entities;
protected readonly DbSet<T> _dbset; // error in this line
public GenericRepository(BlazorContext context)
{
_entities = context;
_dbset = context.Set<T>();
}
public IEnumerable<T> GetAll()
{
return _dbset.AsEnumerable();
}
}
}
Below is my GenericUnitOfWork
namespace Blazor.Repository.Implementation
{
public sealed class GenericUnitOfWork : IGenericUnitOfWork, IDisposable
{
private BlazorContext entities = null;
public GenericUnitOfWork()
{
entities = new BlazorContext();
}
public Dictionary<Type, object> repositories = new Dictionary<Type, object>();
public IGenericRepository<T> Repository<T>() where T : class
{
if (repositories.Keys.Contains(typeof(T)) == true)
{
return repositories[typeof(T)] as IGenericRepository<T>;
}
var t = typeof(T);
IGenericRepository<T> repo = new GenericRepository<T>(entities);//error in this line
repositories.Add(typeof(T), repo);
return repo;
}
}
}

Your connection string template is not correct for the MS SQL server. Try to use something like this:
"Data Source=localhost;Initial Catalog=BlazorDB;Integrated Security=SSPI;Persist Security Info=True;"
If it doesn't work then you use not MS SQL server and so in your startup you have to replace "item => item.UseSqlServer" with other provider.

Related

C# Tests with EF InMemory Database System.InvalidOperationException

I'm trying to use EF Core InMemory Database and XUnit in my integration tests, but unfortunately, I'm getting this Exception:
System.InvalidOperationException : Relational-specific methods can only be used when the context is using a relational database provider.
This is the Class that uses the WebApplicationFactory:
public class TestFactory<TProgram, TDbContext> : WebApplicationFactory<TProgram>
where TProgram : class where TDbContext : DbContext
{
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureTestServices(services =>
{
services.RemoveDbContext<TDbContext>();
services.AddDbContext<TDbContext>(options =>
{
options.UseInMemoryDatabase(Guid.NewGuid().ToString());
});
});
}
}
This is the base Class used in the Test Classes:
public class TestFactoryBase : IClassFixture<TestFactory<Program, CDbContext>>
{
public HttpClient _client;
public CDbContext _dbContext;
public TestFactoryBase(TestFactory<Program, CDbContext> factory) {
_client = factory.CreateClient();
_dbContext = factory.Services.GetService<CDbContext>();
}
}
This is the Test Class:
public class RolesControllerTest : TestFactoryBase
{
private IRoleRepository _rolesRepository;
public RolesControllerTest(TestFactory<Program, CDbContext> factory) : base(factory)
{
_rolesRepository = CreateRoleRepository(_dbContext);
}
// Tests Here!
}
How can I solve this exception?

System.ArgumentNullException when GetDbContext in constructor

I'm trying to use Entity Framework Core with ASP.NET Boilerplate .NET Core, but I don't want to use Repository built-in functions.
There is a problem with my DB context; it keeps returning:
System.ArgumentNullException: 'Value cannot be null.'
for the DbContext instance as shown below:
public class MainProjectsAppService : ApplicationService
{
private readonly DecentralizationDbContext _ctx;
public MainProjectsAppService(IDbContextProvider<DecentralizationDbContext> dbContextProvider)
{
_ctx = dbContextProvider.GetDbContext();
}
public void CustomizedCreateMainProject(MainProject mainProject)
{
MainProject customizedMainProject = new MainProject
{
...
};
_ctx.MainProjects.Add(customizedMainProject);
_ctx.SaveChanges();
}
}
Below is the DbContext class code:
namespace Decentralization.EntityFrameworkCore
{
public class DecentralizationDbContext : AbpZeroDbContext<Tenant, Role, User, DecentralizationDbContext>
{
/* Define a DbSet for each entity of the application */
public DbSet<MainProject> MainProjects { get; set; }
public DecentralizationDbContext(DbContextOptions<DecentralizationDbContext> options)
: base(options)
{
}
}
}
Do not call dbContextProvider.GetDbContext() in the constructor.
Define a getter instead:
public class MainProjectsAppService : ApplicationService
{
private readonly IDbContextProvider<DecentralizationDbContext> _dbContextProvider;
private DecentralizationDbContext _ctx => _dbContextProvider.GetDbContext();
public MainProjectsAppService(IDbContextProvider<DecentralizationDbContext> dbContextProvider)
{
_dbContextProvider = dbContextProvider;
}
}
Reference: aspnetboilerplate/aspnetboilerplate#4809

Repository pattern with multiple databases

I am using repository pattern on EF Core and Autofac in a windows service.
I have a service that needs to connect with the some dozen databases which have the same schema (same dbcontext) but only different data.
How can I achieve this in my service using Autofac? Belo
public class ReportRepository : IReportRepository
{
private readonly ReportDbContext dbContext;
public ReportRepository(ReportDbContext dbContext)
{
this.dbContext = dbContext
}
public SomeModel GetData()
{
return dbContext.SalesData;
}
}
public class ReportService : IReportService
{
private readonly IReportRepository reportRepositoryEUServer;
public ReportService(IReportRepository reportRepositoryEUServer)
{
this.reportRepositoryEUServer = reportRepositoryEUServer
}
public SomeModelDto GenerateReport()
{
var euData = reportRepositoryEUServer.GetData();
// I need to call other servers (e.g LATAM) here and get the data and aggregate them with euData
}
}
Create base context including all settings, dbsets etc:
public abstract class BaseContext : DbContext
{
public BaseContext(DbContextOptions options)
: base(options)
{ }
public DbSet<object> FirstSet { get; set; }
...
}
inherit from BaseContext for both DBs
public class LATAMContext : BaseContext
{
public LATAMContext(DbContextOptions<LATAMContext> options) : base(options)
{
}
}
public class EUContext : BaseContext
{
public EUContext(DbContextOptions<EUContext> options) : base(options)
{
}
}
and register both in Startup.cs
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddDbContext<LATAMContext>(options => options.UseSqlServer(Configuration.GetConnectionString("LATAMConnectionString")));
services.AddDbContext<EUContext>(options => options.UseSqlServer(Configuration.GetConnectionString("EUConnectionString")));
// Autofac
var builder = new ContainerBuilder();
// needed only if you plan to inject ICollection<BaseContext>
builder.RegisterType<LATAMContext>().As<BaseContext>();
builder.RegisterType<EUContext>().As<BaseContext>();
builder.Populate(services);
return new AutofacServiceProvider(builder.Build());
}
add connection strings in appsettings.json
"ConnectionStrings": {
"LATAMConnectionString": "Server=(localdb)\\mssqllocaldb;Database=ContosoUniversity1;Trusted_Connection=True;MultipleActiveResultSets=true",
"EUConnectionString": "Server=(localdb)\\mssqllocaldb;Database=ContosoUniversity1;Trusted_Connection=True;MultipleActiveResultSets=true"
}
and now you can inject both contexts
public class ReportRepository : IReportRepository
{
private readonly LATAMContext latamDbContext;
private readonly EUContext euDbContext;
public ReportRepository(LATAMContext latamDbContext, EUContext euDbContext)
{
this.latamDbContext = latamDbContext;
this.euDbContext = euDbContext;
}
}
or if you plan to inject collection of contexts
public class ReportRepository : IReportRepository
{
private readonly ICollection<BaseContext> dbContexts;
public ReportRepository(ICollection<BaseContext> dbContexts)
{
this.dbContexts = dbContexts;
}
}
to access specific context
var _euContext = dbContexts.FirstOrDefault(x => x is EUContext) as EUContext;
var _latamContext = dbContexts.FirstOrDefault(x => x is LATAMContext) as LATAMContext;

How to use Generic CRUD in Entity Framework using DI

I wanna to try generic but I get some problem.
and this is my step
step 1. I create a database Model also inheritance class
public class DBRepo { }
public partial class UserAccount : DBRepo
{
public int Id { get; set; }
public string Account { get; set; }
public string Pwd { get; set; }
}
step 2. I wish all CRUD action can using this interface. so I do this
public class DBServices
{
public interface IDBAction<TEntity> where TEntity : DBRepo
{
void InsertData(TEntity entity);
}
public class dbCRUD<TEntity> : IDBAction<TEntity> where TEntity : DBRepo
{
private readonly CoreContext _db;
private DbSet<TEntity> dbSet;
public dbCRUD(CoreContext _db)
{
this._db = _db;
this.dbSet = _db.Set<TEntity>();
}
public void InsertData(TEntity _entity)
{
this.dbSet.Add(_entity);
this._db.SaveChanges();
}
}
}
and then I usine ServiceProvider like
ServiceProvider provider = new ServiceCollection()
.AddSingleton<IDBAction<DBRepo>>()
.BuildServiceProvider();
provider.GetService<IDBAction<DBRepo>>().InsertData(_ua);
and I'll get this error
Cannot instantiate implementation type ....
so I change to try other way like.
in Constructor
private readonly IDBAction<DBRepo> dBAction;
public HomeController( IDBAction<DBRepo> _dBAction)
{
this.dBAction = _dBAction;
}
....
this.dBAction.InsertData(_ua);
sure.I get error again
InvalidOperationException: Unable to resolve service for type...
have some can teach me how to fix the problem?
-> Update
I try to change like but it's failed
ServiceProvider provider = new ServiceCollection()
.AddScoped<IDBAction<DBRepo>, dbCRUD<DBRepo>>()
.AddScoped<CoreContext>()
.BuildServiceProvider();
error same this
Unable to resolve service for type...
it's my DBContext
public virtual DbSet<UserAccount> UserAccount { get; set; }
public CoreContext(DbContextOptions<CoreContext> options)
: base(options)
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer(#"Connection String");
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<UserAccount>(entity =>
{
entity.Property(e => e.Account).IsRequired();
entity.Property(e => e.Pwd)
.IsRequired()
.HasMaxLength(20);
});
}
You are registering it in the wrong way. You must provide the implementation of your (generic) and also the DbContext must be registered.
ServiceProvider provider = new ServiceCollection()
.AddSingleton<IDBAction<DBRepo>, dbCRUD<DBRepo>>()
.BuildServiceProvider();
provider.GetService<IDBAction<DBRepo>>().InsertData(_ua);
Also registering it as a singleton will cause problems with change-tracking of entity-framework. So you should register it like this:
ServiceProvider provider = new ServiceCollection()
.AddScoped<IDBAction<DBRepo>, dbCRUD<DBRepo>>()
.AddScoped<CoreContext>()
.BuildServiceProvider();
provider.GetService<IDBAction<DBRepo>>().InsertData(_ua);
You could also implement a real generic like this
public interface IEntity
{
Guid Id { get; set; }
}
public class DbAction<TEntity> : IDbAction<TEntity> where TEntity: class, IEntity, new()
{
public void InsertData(TEntity entity)
{
...
}
}
Now register it as a generic
ServiceProvider provider = new ServiceCollection()
.AddScoped(typeof(IDbAction<>), typeof(DbAction<>))
.AddScoped<CoreContext>()
.BuildServiceProvider();
provider.GetService<IDBAction<DBRepo>>().InsertData(_ua);
Small example, but would work.
Edit:
DbContextOptions must of course be passed to the DbContext for the IoC to work.
.AddDbContext<CoreContext>(options => options.UseSqlServer("my-conntection-string")); // change provider if necessary, this will only work with MS SQL Server

show Method name expected when using StructureMap

i using StructureMap in my project for using DepencyInjection . I have 5 project in my solution.
I have IUnitOfWork interface in DAL and I Defnation Function of IUnitOfWork in ApplicationDbContext .
ApplicationDbContext :
public class ApplicationDbContext : DbContext, IUnitOfWork
{
public ApplicationDbContext()
: base("ApplicationDBContext")
{
}
public virtual DbSet<User> Users { get; set; }
public void ForceDatabaseInitialize()
{
Database.Initialize(true);
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
#region IUnitOfWork Members
public void MarkAsDeleted<TEntity>(TEntity entity) where TEntity : class
{
Entry(entity).State = EntityState.Deleted;
}
public new IDbSet<TEntity> Set<TEntity>() where TEntity : class
{
return base.Set<TEntity>();
}
.
.
.
now when I want to register IUnitOfWork in main project :
public static class StructureMapDefnation
{
private static readonly Lazy<Container> _containerBuilder =
new Lazy<Container>(defaultContainer, LazyThreadSafetyMode.ExecutionAndPublication);
public static IContainer Container
{
get { return _containerBuilder.Value; }
}
private static Container defaultContainer()
{
var container = new Container(ioc =>
{
// map same interface to different concrete classes
ioc.For<IUser>().Use<EfUserService>();
ioc.For<IUnitOfWork>().Use(() => new ApplicationDbContext())();
});
container.AssertConfigurationIsValid();
return container;
}
}
it show me this error :
Severity Code Description Project File Line Suppression State
Error CS0149 Method name expected BimehKosarFinal E:\myproject\BimehKosarFinal\BimehKosarFinal\StructureMap\StructureMapDefnation.cs 28 Active
in this line :
ioc.For<IUnitOfWork>().Use(() => new ApplicationDbContext())();
whats the problem ? how can I solve this problem ?
remove the last (), and write
ioc.For<IUnitOfWork>().Use(() => new ApplicationDbContext());
Or
ioc.For<IUnitOfWork>().Use<ApplicationDbContext>();

Categories

Resources