Currently i am working on a .Net core 3.1 App. I am using below code in the startup to Add the Dbcontext.
services.AddDbContext<sampleContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
As this is the code first approach i have below code in the Dbcontext
public class sampleContext: DbContext
{
public sampleContext()
{
}
public sampleContext(DbContextOptions<sampleContext> options) : base(options){ }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer(Environment.GetEnvironmentVariable("DefaultConnection", EnvironmentVariableTarget.Process));
}
}
}
When i am running the API, its working as expected as optionsBuilder.IsConfigured=true.
Appsettings.json
{
"ConnectionStrings": {
"DefaultConnection": "Server=(localdb)\\MSSQLLocalDB;Initial Catalog=sampleDb; Integrated Security=true;"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"UploadFAUrl": "http://localhost:7071/Api"
}
Coming to issue:-
When i am running the CLI command ADD-MIGRATION sampleCongetting **Value cannot be null. (Parameter 'connectionString')**
Whys is so? As we will be moving to different env, we may need to run this command. Atleast in local, we need to run the command. How to fix this issue? Referred some of the question but non helped. PLease suggest if i am missing anything.
The EF Core command line tools, will attempt to locate all required services and configuration, based on your current project. By looking for your CreateHostBuilder method, and calling it;
public static IHostBuilder CreateHostBuilder(string[] args) => ...
You shouldn't need to override OnConfiguring. But you may need to provide an explicit --startup-project command line parameter.
Do you have multiple projects?
Mark the project Set as startup project which contains Appsettings.json.
Related
I've been trying to create a migration and then update the database (using EF Core tools and SSMS to check the database). I've been struggling because I have different projects. The organization of my solution is the following:
I want to have the migration and the related DB interactions in VSC.Repo. This means that the context is in this project. Besides that, I have my connection string in the default appsettings, which is in VSC.API (different assembly). I've tried various ways of trying to get the connection string from there, but I always get the following error when I run the "dotnet ef database update" in the VSC.Repo project:
This is my context class:
public class DataContext : DbContext
{
private readonly string connectionString;
public DataContext()
{
}
public DataContext(DbContextOptions<DataContext> options, IConfiguration configuration) : base(options)
{
connectionString = configuration.GetSection("ConnectionStrings:DefaultConnection").Value;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(connectionString);
}
I can't figure out what I'm doing wrong. Any help would me much appreciated.
EDIT: With the hardcoded string it works perfectly fine, but this is bad practice and I don't want to implement this way.
appsettings.json:
"ConnectionStrings": {
"DefaultConnection": "server=localhost;database=vscDatabase;trusted_connection=true;TrustServerCertificate=True;"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
program.cs:
WebApplicationBuilder? builder =
WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
var connectionString =
builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<DataContext>(options =>
options.UseSqlServer(connectionString));
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
//builder.AddRepoConfigurations();
var app = builder.Build();
Okay so #Panagiotis Kanavos found out that I was executing the command in the wrong project, more precisely, in one that did not have the program.cs, and this was the issue. When I executed in the correct one, it worked just fine.
I am starting a web api which uses postgres as the backend.
I am on a team of developers that will each have a local db for development. How can I ensure that if a new developer comes on the team that their local db is created without manually creating it themself.
As of right now, we each created our local db's through command line and update our appsettings.Development.json to use our local db connection string (which is on the gitignore incase we use sensitive passwords).
It's annoying to have to manually set this portion up however. Is there anyway to just have a database be created on the fly? As in, right when they launch the API, the db should be created and the migrations applied onto it.
appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"Local": "Server=localhost;Port=5432;Database=mydb;User ID=xxx;Password=xxx;"
}
}
Startup.cs
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
UpdateDatabase(app);
// Other configurations
}
public virtual void UpdateDatabase(IApplicationBuilder app)
{
using var serviceScope = app.ApplicationServices
.GetRequiredService<IServiceScopeFactory>()
.CreateScope();
using var context = serviceScope.ServiceProvider.GetService<MyDbContext>();
context.Database.EnsureCreated();
context.Database.Migrate();
}
I created a asp.net core web api project that has Microsoft.EntityFrameworkCore.SqlServer, Microsoft.EntityFrameworkCore.Tools, and System.Configuration.ConfigurationManager. I ran the Scaffolding command Scaffold-DbContext "Data Source=DEX-LEP3LOXH0M5\\SQLEXPRESS;Initial Catalog=LibraryStore;Integrated Security=True" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models.
In Context.cs file that was created from the scaffolding cmd created this method:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
//#warning To protect potentially sensitive information in your connection string, you should move it out of source code. You can avoid scaffolding the connection string by using the Name= syntax to read it from configuration - see https://go.microsoft.com/fwlink/?linkid=2131148. For more guidance on storing connection strings, see http://go.microsoft.com/fwlink/?LinkId=723263.
optionsBuilder.UseSqlServer("Data Source=DEX-LEP3LOXH0M5\\SQLEXPRESS;Initial Catalog=LibraryStore;Integrated Security=True");
}
}
when I ran the route path to the controller it worked perfectly I was able to see the records from the DB. But on that #warning message, it provided a link which I followed. In my appsettings.json file I added ConnectionStrings by doing:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"Default": "Data Source=DEX-LEP3LOXH0M5\\SQLEXPRESS;Initial Catalog=LibraryStore;Integrated Security=True"
}
}
then my next step was to add the code in the ConfigureServices in the startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "LibraryWebAPI", Version = "v1" });
});
services.AddDbContext<LibraryStoreContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("Default")));
}
then it said to change the OnConfiguring() in the Context.cs file that was created.
I did the following:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer(ConfigurationManager.ConnectionStrings["Default"].ConnectionString);
}
}
but then it generates the error message on the line optionsBuilder:
System.Configuration.ConnectionStringSettingsCollection.this[string].get returned null.
Is there a reason why it is returning null if the same connection string worked before following the link to add connection to connectionstring in appsettings?
including my controlller:
[HttpGet]
[Route("GetAllDetails")]
public IEnumerable<LibraryInfo> GetDetails()
{
using (var context = new LibraryStoreContext())
{
// get all library details
return context.LibraryDetails.ToList();
}
}
I did just find a more comfortable way to maintain generating migrations, where you don't have to run the command from the web project.
DbContext
internal class ContosoContext : DbContext
{
private readonly IConfiguration configuration;
public ContosoContext(IConfiguration configuration)
{
this.configuration = configuration;
}
public ContosoContext()
{
this.configuration = null;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
if (configuration == null)
{
// Only used when generating migrations
// Contoso.Data = name of the project where your migrations should reside
var migrationsConnectionString = #"Server=(localdb)\mssqllocaldb;Database=Contoso;Trusted_Connection=True;ConnectRetryCount=0";
optionsBuilder.UseSqlServer(migrationsConnectionString, options => options.MigrationsAssembly("Contoso.Data"));
}
else
{
optionsBuilder.UseSqlServer(configuration.GetConnectionString("Contoso"));
}
}
}
Registration of the DbContext
services.AddDbContext<ContosoContext>(options => {
options.UseSqlServer(Configuration.GetConnectionString("Contoso"));
});
When running the application (the web project), the constructor with parameters will be called.
When generating migrations from the Contoso.Data folder (dotnet ef migrations add myawesomemigration), the parameterless constructor will be called.
This drops the need of excessively specifying paramters during the generation of database migrations:
dotnet ef migrations add AddIdentity
The .Net Core application uses appsettings.json instead of web.config file.
Because .Net Core applications are self hosted and can almost run on any platform, they are no longer have to be hosted on IIS. The .Net Core application settings are stored in a Json format (appsettings.json) by default while .Net Framework application configurations are stored in a web.config file in XML format
This is why it shouldn't work with your appsettings.json when using ConfigurationManager
From the guid you sent they say to do the change in protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
But this is said not on .net core applications
I developed a code where I do some http request. I used to hard coded the url which i used for the http calls but i want to make it more efficient. What I did is:
Updated the appsettings.json file:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"urls": "http://localhost:5002",
}
Added the urls field.
Created a field in the class where i want the url:
private readonly string _url = ConfigurationManager.AppSettings["urls"];
Program.cs class
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
webBuilder.UseUrls("http://localhost:5002");
});
}
In order to get the url from appsettings, and then pass the _url variable where i want to use it in the class. However for some reason im getting null value when im trying to run the program. Am I doing something wrong? and is there any better solution than that?
Thank you in advance
The way the appsettings.json loads into the app builder is different then .NET Framework.
But this has been answered in another post.
See How to read AppSettings values from a .json file in ASP.NET Core.
What you can do to avoid this problem is to use Microsoft.Extensions.Configuration class to retreive your data from appsettings.json .
Probably you will need also to inject the Configuration in your controller class as show below
private readonly IConfiguration _config;
public ConfigurationController(IConfiguration config)
{
_config = config;
}
Now you can retrieve your data using the code below :
_config.GetValue<string>("urls");
I am trying to scaffold and I get the following error:
There was an error running the selected code generator: 'No parameterless constructor defined for type 'MvcProduct.Data.MvcProductContext'.'
Here you can see an image of it:
The following is my MvcProductContext:
using Microsoft.EntityFrameworkCore;
using MvcProduct.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace MvcProduct.Data
{
public class MvcProductContext : DbContext
{
public MvcProductContext(DbContextOptions<MvcProductContext> options)
: base(options)
{
}
public DbSet<Product> Product { get; set; }
}
And the appsettings.json:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"MvcProductContext": "Server=(localdb)\\mssqllocaldb;Database=MvcProductContext-1;Trusted_Connection=True;MultipleActiveResultSets=true"
}
ConfigureServices method in Startup.cs file:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddDbContext<MvcProductContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("MvcProductContext")));
}
I have also tried to add a a second constructor in MvcProductContext class. (Something which I would like to avoid and don't want to do) A second contructor without any parameter. But if I do that I just get another error which says:
There was an error running the selected code generator: 'No database provider has been configured for this DbContext. A provider can be configured bu overriding the DbContext.OnConfiguring method or by using AddDbContext on the application service provider. If AddDbContext on the application service provider. If AddDbContext is used, then also ensure that your DbCotnext type accepts a DbContextOptions<TContext> object in its constructor and passes it to the base constructor for DbContext.
Microsoft is does the same. They are scaffolding an MVC controller with views, using Entity Framework. They are doing it without adding a second constructor in their MvcMovieCOntext class. Their MvcMovieContextClass corresponds to my MvcProductContext class.
Any help would be appreciated.
Just add a IDesignTimeDbContextFactory implementation to your project and try scaffolding again. It will take care of instantiating your DbContext.
public class DesignTimeDbContextFactory : IDesignTimeDbContextFactory<MvcProductContext>
{
public MvcProductContext CreateDbContext(string[] args)
{
IConfigurationRoot configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appSettings.json")
.Build();
var builder = new DbContextOptionsBuilder<MvcProductContext>();
var connectionString = configuration.GetConnectionString("MvcProductContext");
builder.UseSqlServer(connectionString);
return new MvcProductContext(builder.Options);
}
}
In .net core 6 :
Install 4 packages:
1.Microsoft.EntityFrameworkCore.SqlServer
2.Microsoft.EntityFrameworkCore.Tools
3.Microsoft.EntityFrameworkCore.Design
4.Microsoft.VisualStudio.Web.CodeGeneration.Design
Scaffold the data base and create the DbContext and Entities by scaffold command or ef core power tools vs extension.
Inject your data base settings in program.cs :
builder.Services.AddRazorPages();
builder.Services.AddDbContext<AppDbContext>(options =>
{
options.UseSqlServer(builder.Configuration.GetConnectionString("CS"));
});
Add your connection string to appsettings.json :
"AllowedHosts": "*",
"ConnectionStrings": {
"CS": "Data Source=.\\SQLEXPRESS;Initial Catalog=Db1;Integrated Security=True;MultipleActiveResultSets=True"
}