No Database Provider Error even when DBContext is configured - c#

Mine is a .net core web api project with EF. My plan was to use connection string from Appsettings.json and thus I configured like this in startup.cs
services.AddDbContext<dbLNePMODev1Context>(options => {
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
});
Also here is how my DBContext constructor looks like
public partial class dbLNePMODev1Context : DbContext
{
public dbLNePMODev1Context()
{
}
public dbLNePMODev1Context(DbContextOptions<dbLNePMODev1Context> options)
: base(options)
{
}
....
.....
}
But even then I am getting the following error when trying to connect with DB
'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.'
Sorry I believe I could be missing something since I am new to EF. Please help me what I did wrong here.

Related

Entity framework migrations errors

I want to create a migration for existing entities.
I have a DataContext class
public class DataContext : DbContext
{
public DataContext()
{
}
public DataContext(DbContextOptions<DataContext> options) : base(options)
{
}
public DbSet<AppUser> Users { get; set; }
}
And I added it to the services in IServiceCollection extension method -
public static class DependencyInjection
{
public static IServiceCollection AddInfrastructure(this IServiceCollection services, IConfiguration configuration)
{
services.AddDbContext<DataContext>(options =>
{
options.UseSqlServer(configuration.GetConnectionString("DefaultConnection"),
b => b.MigrationsAssembly(typeof(DataContext).Assembly.FullName));
});
return services;
}
}
When I try to add a migration from Entity Framework command tool -
"dotnet ef migrations add InitialCreate" such error occurs:
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.
Can't really understand what's wrong with my code. It actually works by overriding OnConfiguring method but I need a solution for this kind of approach. Any ideas?
Try to remove the default public constructor (the parameterless one).
When you execute the CLI command you have some additional options like --project and --startup-project. By specifying them it will enable the use of the host builder to create your DB context, and you don't need this parameterless constructor.
The ef cli is using reflection to look into your project and then executes the host builder setup in order to have a service builder. From there it will instantiate the DB context. If it doesn't work. It will fall back first to a design time factory. And finally will use the default constructor (which is happening in this case).

EF Core Migration with multiple provider always runs SQL Server scripts

I am using EF Core Code first and I have an issue when using multiple DB providers (SQL Server and MySql).
Even when I choose to use MySql DB provider, SQL server migration files are used.
Check the sample project
In my case, I use the same migration for both providers but sometimes I need to do some changes to migration files manually. for example added annotation for both providers (or change the type of some fields like varchar to nvarchar).
Id = table.Column<int>(nullable: false)
.Annotation("MySql:ValueGeneratedOnAdd", true)
.Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
For me it's work fine
Writing provider-specific migrations, database initializers, and services with Entity Framework core can be a difficult task. Use AdaptiveClient to greatly simplify the process. AdaptiveClient is a utility that works with Autofac for provisioning a service layer against multiple database providers or transports. AdaptiveClient.EntityFrameworkCore is an add-on that includes utilities for working with Entity Framework Core. In a nutshell here is how it AdaptiveClient works:
IMigrationContext is a placeholder interface that allows you to associate your DbContext with a specific provider (MSSQL, MySql, etc) for the purpose of creating a migration.
IDbContextOptions is a placeholder interface that allows you to associate an implementation of DbContextOptions that is specific to your provider.
RegistrationHelper is a utility that simplifies registering your components with Autofac. RegisterMigrationContext is a method you can call to easily register your provider-specific migration context.
To create provider-specific migrations you create a class for each database provider you want to target. These classes derive from your DbContext and implement IMigrationContext (which has no members):
public class MyDbContext_MSSQL : MyDbContext, IMigrationContext
{
public MyDbContext_MSSQL(DbContextOptions options) : base(options)
{
}
}
public class MyDbContext_MySQL : MyDbContext, IMigrationContext
{
public MyDbContext_MySQL(DbContextOptions options) : base(options)
{
}
}
The examples above are complete - you do not have to write any additional code. You do not need to create a separate DbContext for each provider (unless you wish to do so). The reason you need to create a class for each provider is because EF reflects on your assembly to find the correct DbContext when you run dotnet ef migrations add....
Create classes that wrap DbContextOptions and implement IDbContextOptions:
public class DbContextOptions_MSSQL : IDbContextOptions
{
public DbContextOptions Options { get; set; }
public DbContextOptions_MSSQL(string connectionString)
{
DbContextOptionsBuilder builder = new DbContextOptionsBuilder();
builder.UseSqlServer(connectionString);
Options = builder.Options;
}
}
public class DbContextOptions_MySQL : IDbContextOptions
{
public DbContextOptions Options { get; set; }
public DbContextOptions_MySQL(string connectionString)
{
DbContextOptionsBuilder builder = new DbContextOptionsBuilder();
builder.UseMySql(connectionString);
Options = builder.Options;
}
}
Use the AdaptiveClient RegistrationHelper to register your classes with Autofac:
registrationHelper.RegisterMigrationContext<Database.Db_MSSQL>(API_Name.MyAPI, DataBaseProviderName.MSSQL);
registrationHelper.RegisterMigrationContext<Database.Db_MySQL>(API_Name.MyAPI, DataBaseProviderName.MySQL);
registrationHelper.RegisterDbContextOptions<DbContextOptions_MSSQL>(DataBaseProviderName.MSSQL);
registrationHelper.RegisterDbContextOptions<DbContextOptions_MySQL>(DataBaseProviderName.MySQL);
In the code above API_Name is just a constant that resolves to a simple string like "MyApplicationName". Same with DataBaseProviderName.MSSQL and .MySQL. They are string constants that resolve to "MSSQL" or "MySQL".
Now, here is the most important part: Just as you register the components of your application using keys such as "MSSQL" or "MySQL", you also register the connection strings for your application using those same constants.
This allows Autofac to resolve the correct provider-specific or transport-specific components based on nothing more than the connection string currently in use for application. You can read up on the entire process here.
You can see the complete working example in the Zamagon Demo. The demo illustrates migrations, database initializers, and drop-and-recreate scenarios for integration testing.

Why does EF7 say I haven't configured any providers, when ASP.net Identity is working fine with the same DbContext?

I've just started work on an experimental project using ASP.net 5, MVC6 and Entity Framework 7. I have ASP.Net Identity working fine, but then tried to add some of my own data to the DbContext and hit this problem. EF7 reports:
An unhandled exception occurred while processing the request.
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.
Microsoft.Data.Entity.Internal.DatabaseProviderSelector.SelectServices(ServiceProviderSource
providerSource) Stack Query Cookies Headers
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.
Here's my configuration method:
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddApplicationInsightsTelemetry(Configuration);
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]));
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.AddMvc();
// Add application services.
services.AddTransient<IEmailSender, AuthMessageSender>();
services.AddTransient<ISmsSender, AuthMessageSender>();
services.AddTransient<ApplicationUnitOfWork>(instance => new ApplicationUnitOfWork());
}
ApplicationUnitOfWork is a façade over EF7 to reduce tight coupling. Here's the whole thing so far:
public class ApplicationUnitOfWork : IUnitOfWork
{
readonly ApplicationDbContext dbContext;
public ApplicationUnitOfWork()
{
dbContext = new ApplicationDbContext();
Products = new ProductRepository(dbContext);
}
public void Dispose() { dbContext.Dispose(); }
public IUserRepository Users { get; }
public IRepository<SoftwareProduct> Products { get; }
public async Task CommitAsync() { await dbContext.SaveChangesAsync(); }
public void Cancel() { throw new NotImplementedException(); }
}
Now when I run the web application, I am able to register a user account and log in and EF creates the database, creates the Identity tables and populates them with user data. The products table is also created - so clearly at some level EF is able to use the ApplicationDbContext and find a provider which it uses to create the database and schema.
However when I try to access my Products controller, which uses the ProductsRepository, EF complains - even though ApplicationDbContext is used in both cases and was used to create the database!
So how come? What's special about ASP.net Identity that it can somehow obtain a provider, but my own code can't? What "magic incantation" am I missing?
its because you are newing it up instead of having it injected for you. The one you are newing up hasn't been configured.
You should change your class to have it passed into the constructor.
DbContext has more than one constructor and you are using the empty one which doesn't configure it.
Better to let it be injected by making your constructor like this:
public ApplicationUnitOfWork(ApplicationDbContext context)
{
dbContext = context;
Products = new ProductRepository(dbContext);
}
your code shows that ApplicationDbContext has been registered with the DI, Identity is using the injected one but you are not since you newed it up yourself with the parameterless constructor
you should also register your ApplicationUnitOfWork so it can be injected:
services.AddScoped<ApplicationUnitOfWork, ApplicationUnitOfWork>();

Correct using of DBContext

I have an application where multiple users can login. For that I have a kind of session object that stores a DBContext object. But the problem is, that the cached DBContext stores only the data of the logged user. When another user are also logged in, then the cached data is maybe older because it will be changed by the second user.
Is there a conceptional way to handle this. Instead of caching the DBContext object, I can create it every time I do an database request. Is this the correct way or is there a kind of event to catch to know that the database content is changed?
You should not be caching the DbContext object in any way. DbContext maintains state internally for multiple users automatically.
You create a new context when you open a controller to respond to a user request for data. In Entity Framework 6 this would look like
public class FeedItemController : ApiController
{
private LynxFeedAPI_Context db = new LynxFeedAPI_Context();
// GET api/FeedItem
public IQueryable<FeedItem> GetFeedItems()
{
return db.FeedItems;
}
It is done differently in EF 7 where Startup.cs is used to setup the Dependency Injection
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
// Uncomment the following line to add Web API services which makes it easier to port Web API 2 controllers.
// You will also need to add the Microsoft.AspNet.Mvc.WebApiCompatShim package to the 'dependencies' section of project.json.
// services.AddWebApiConventions();
services.Configure<AppSettings>(configuration.GetConfigurationSection("AppSettings"));
// Add EF services to the services container.
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(configuration["Data:DefaultConnection:ConnectionString"]));
services.AddSingleton<IApplicationDbContext, ApplicationDbContext>();
services.AddSingleton<IProposalDataRepository, ProposalDataRepository>();
services.AddSingleton<IPositionDataRepository, PositionDataRepository>();
services.AddSingleton<IMandatoryReqDataRepository, MandatoryReqDataRepository>();
services.AddSingleton<IRatedReqDataRepository, RatedReqDataRepository>();
}
and is used by the controller
public class ProposalController : Controller
{
private readonly IProposalDataRepository repProposal;
public ProposalController(IProposalDataRepository repository) {
repProposal = repository;
}
[HttpGet]
public IEnumerable<Proposal> GetAll()
{
return repProposal.SelectAll();
}
where it is not necessary to ever make a call to create a new DbContext

EF6 Application Code

I'm migrating to Entity Framework v6 and I'm struggling to build code that will let me define my SQL 2008R2 database connection in the code. I cannot store the connection string information within the app.config file due to this library being a dll that multiple applications will be using. The idea is to maintain all the Database connections within 1 dll without having to reference the entity-libraries in the front-ends nor specify a connection string.
With EF5 I was able to use a partial class and define the connection string in the DBContext, that method does not seem to work with EF6. I'd like an example of an EF6 SQL database connection entirely defined within code. Most of the examples of EF6 out there are for code-first models, I already have the database tables, I just need to build the interface.
-Hiram
(assuming that you are using the EF Designer)
You can't just pass a connection string to the DbContext when using the code generated from the EF6 Designer because the DbContext needs the information created from the EDMX. But you can still create a partial class that has a constructor that accepts a connection string. You will just have to create an ObjectContext and pass that to the DbContext constructor.
Here is an example:
using System.Data.Entity.Core.EntityClient;
using System.Data.Entity.Core.Metadata.Edm;
using System.Data.Entity.Core.Objects;
using System.Data.SqlClient;
namespace Northwind.Model {
public partial class NorthwindEntities {
public NorthwindEntities(string connectionString)
: base(GetObjectContext(connectionString), true) {
}
private static ObjectContext GetObjectContext(string connectionString) {
// You can use the metadata portion of the connection string the the designer added to your config for the paths
var paths = new[] {
"res://*/Northwind.csdl",
"res://*/Northwind.ssdl",
"res://*/Northwind.msl"
};
var workspace = new MetadataWorkspace(paths, new[] { typeof(NorthwindEntities).Assembly });
var connection = new EntityConnection(workspace, new SqlConnection(connectionString));
return new ObjectContext(connection);
}
}
}
You can still define the connection string in the DBContext in EF6.
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext()
: base(#"Your connection string here") { }
// Rest of your DbContext code
}
But hard coding a connection string in there isn't very versatile. Even though your DbContext will be in it's own dll, it can still read the app.config or web.config of your primary project if it is in the same solution (and I'm fairly sure it will work even if you add your DbContext dll as a reference).
Just add a reference to System.Configuration in your DbContext project, and then you can get at the connection string with either ConfigurationManager.ConnectionStrings["MyConnectionStringName"].ConnectionString or ConfigurationManager.AppSettings["MyConnectionStringName"]
And you would store the connection string in your primary applications web.config in the <connectionStrings> section OR in the 'app.config' in the <appSettings> section
Note that if you do it this way (by reading from web.config or app.config), you should change your DbContext code accordingly:
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext()
: base("MyConnectionStringName") { }
// Rest of your DbContext code
}

Categories