Why am i getting argumentNullException when adding migration - c#

I'm trying to create a migration in my web api for one-to-many db. Services are configured this way and the connection string is successfully received from launchsettings.json
var connectionStr = Environment.GetEnvironmentVariable("ApplicationDbContext");
services.AddDbContext<InsolationResultContext>(options =>
{
options.UseNpgsql(connectionStr, builder =>
{
builder.CommandTimeout(300);
builder.EnableRetryOnFailure(5, TimeSpan.FromSeconds(10), null);
});
});
This are models
public class DocumentInsolationResult
{
public string Id { get; set; }
public string UserId { get; set; }
public IEnumerable<InsolationResult> Elements { get; set; }
}
public class InsolationResult
{
public string UniqueId { get; set; }
public string Insolation { get; set; }
}
And DbContext
public class InsolationResultContext : DbContext
{
public DbSet<DocumentInsolationResult> DocumentInsolationResults { get; set; }
public DbSet<InsolationResult> InsolationResults { get; set; }
public InsolationResultContext(DbContextOptions<InsolationResultContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<DocumentInsolationResult>()
.HasMany(p => p.Elements)
.WithOne();
}
}
the connection string looks like this:
"environmentVariables": {
"ApplicationDbContext": "Host=192.168.1.***;Port=****;Database=***.******;Username=*****;Password=****",
"ASPNETCORE_ENVIRONMENT": "Development"
},
When trying to "Add-Migartion Init i always get "Value cannot be null. (Paramtere 'connectionString'). What am i doing wrong? Coulnd't actually find the answer on the internet
upd: i'me receiving the connection string from launchsetting, it's ok as i'm using the same way of getting connectionString on some other projects
upd2 hardcoding the connection string worked for me

If you use IConfiguration instead of Environment.GetEnvironmentVariable then it becomes a lot easier:
var connString = config.GetValue<string>("ApplicationDbContext");

It should be
"ConnectionStrings": {
"ApplicationDbContext": "Host=192.168.1.***;Port=****;Database=***.******;Username=*****;Password=****""
}
in appsettings.Development.json file.
Thus it is giving error "Value cannot be null. (Paramtere 'connectionString')."
And in your startup.cs file
services.AddDbContext<InsolationResultContext >(options =>
{
options.UseSqlServer(Configuration.GetConnectionString("ApplicationDbContext")
});

Well the problem was really with the connection string. I couldn't create a migration when using connection string from appsettings or launchsettings. After hardcoding the connection string in stratup.cs i was able to create migration. And now after the db is initialized i'm using connection string from launchsettings. This might be some EF core tricky things.

Related

EF Migration - Unable to create an object of [DbContext]

I have a project which I started but can not seem to create the initial migration. Might just be missing something really stupid.
My Project is layout out like this:
MovieFinder.Core - Contains all the entities
MovieFinder.Infrastructure - Contains the DBContext
Moviefinder.Web - the front end application
This is my DBContext which is in the MovieFinder.Infrastructure project:
using System.Reflection;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using MovieFinder.Core.Entities;
namespace MovieFinder.Infrastructure.Data;
public class MovieContext : DbContext
{
public MovieContext(DbContextOptions<MovieContext> options) : base(options)
{
}
public DbSet<Director> Directors { get; set; }
public DbSet<Episode> Episodes { get; set; }
public DbSet<Genre> Genres { get; set; }
public DbSet<Name> Names { get; set; }
public DbSet<NameProfession> NameProfessions { get; set; }
public DbSet<Principal> Principals { get; set; }
public DbSet<Profession> Professions { get; set; }
public DbSet<Rating> Ratings { get; set; }
public DbSet<Title> Titles { get; set; }
public DbSet<TitleGenre> TitleGenres { get; set; }
public DbSet<TitleName> TitleNames { get; set; }
public DbSet<Writer> Writers { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());
if (Database.ProviderName == "Microsoft.EntityFrameworkCore.Sqlite")
foreach (var entityType in modelBuilder.Model.GetEntityTypes())
{
var properties = entityType.ClrType.GetProperties()
.Where(p => p.PropertyType == typeof(decimal));
var dateTimeProperties = entityType.ClrType.GetProperties()
.Where(p => p.PropertyType == typeof(DateTimeOffset));
foreach (var property in properties)
modelBuilder.Entity(entityType.Name).Property(property.Name)
.HasConversion<double>();
foreach (var property in dateTimeProperties)
modelBuilder.Entity(entityType.Name).Property(property.Name)
.HasConversion(new DateTimeOffsetToBinaryConverter());
}
}
}
I have added the AddDbContext to the ConfigureService method in the Startup.cs in the MovieFinder.Web project.
services.AddDbContext<MovieContext>(opt =>
{
opt.UseSqlite(_config.GetConnectionString("DefaultConnection"),
x => x.MigrationsAssembly("MovieFinder.Infrastructure"));
});
The Connectionstring is stored in the appsettings.development.json file:
{
"ConnectionStrings": {
"DefaultConnection": "Data source=MovieFinder.db"
}
}
So unless I have missed something, I believe I have everything set up. When I run the command dotnet ef migrations add InitialDb -o Data/Migrations --startup-project MovieFinder.Web --project MovieFinder.Infrastructure I get the following error.
Unable to create an object of type 'MovieContext'. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728
Another really helpful Microsoft message. lol

Net 6 Multiple Connection Strings

How to setup in Net 6 program.cs a multiple connection strings?
I want to work with Development, Staging, and Production environments, all of them pointing to different database servers.
NET 6. Program.cs:
builder.Services.AddDbContext<MyContext>(options =>
{
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection"));
});
Thanks in advance.
Here's what you could do.
First, create an appsettings.json like this:
appsettings.json
{
"Kestrel": {
"Endpoints": {
"Http": {
"Url": "http://*:5000"
}
}
},
"WillAppConfig": {
"ActiveEnvironment": "Development",
"DevDatabase": "server:123.123.123.123, user: will, pass:1234",
"STGDatabase": "server:123.123.123.123, user: will, pass:1234",
"ProdDatabase": "server:123.123.123.123, user: will, pass:1234"
}
}
Then create a class somewhere in your project, that will serve to map the configuration to an object.
WillAppConfigurationMap.cs
public class WillAppConfigurationMap
{
public string ActiveEnvironment { get; set; }
public string DevDatabase { get; set; }
public string STGDatabase { get; set; }
public string ProdDatabase { get; set; }
}
Finally in your Program.cs, you could select the connection string to use depending on the value of ActiveEnvironment.
var builder = WebApplication.CreateBuilder(args);
WillAppConfig = builder.Configuration.GetSection("WillAppConfig").Get<WillAppConfigurationMap>();
var connectionString = "";
if (WillAppConfig.ActiveEnvironment == "Development")
{
connectionString = WillAppConfig.DevDatabase
}
else if (WillAppConfig.ActiveEnvironment == "Staging")
{
connectionString = WillAppConfig.STGDatabase
}
else if (WillAppConfig.ActiveEnvironment == "Production")
{
connectionString = WillAppConfig.ProdDatabase
}
builder.Services.AddDbContext<MyContext>(options =>
{
options.UseSqlServer(connectionString));
});
partial class Program
{
public static WillAppConfigurationMap WillAppConfig { get; private set;}
}
You can remove the "Kestrel" section from the appsettings.json if you don't use it. You can use this approach to map any appsettings.json structure.
Then, you can access your configuration object from ANYWHERE in your app doing Program.WillAppConfig.
Create multiple connection strings with different names in appsetting.json:
builder.Services.AddDbContext<MyContext>(options => {
options.UseSqlServer(builder.Configuration.GetConnectionString(UseNameofConnectionString));
});
Also you can create extension method which gives you required connectionString when you call it.

Cosmos dbcontext retrieves empty results

I have a DbContext set up to use Cosmos DB as follows:
public class AuthenticationCosmosDataContext : DbContext, IUnitOfWork
{
private readonly CosmosOptions cosmosOptions;
public DbSet<Settings> Settings { get; set; }
public AuthenticationCosmosDataContext(DbContextOptions<AuthenticationCosmosDataContext> options, IOptions<CosmosOptions> cosmosOptions) : base(options)
{
this.cosmosOptions = cosmosOptions.Value;
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.HasDefaultContainer(cosmosOptions.DefaultContainer);
modelBuilder.Entity<Settings>().ToContainer(cosmosOptions.DefaultContainer);
modelBuilder.ApplyConfiguration(new SettingsConfiguration());
}
Which is set up from Startup.cs like this:
services.AddDbContext<AuthenticationCosmosDataContext>((serviceProvider, options) =>
{
var cosmosOptions = serviceProvider.GetRequiredService<IOptions<CosmosOptions>>().Value;
options.UseCosmos(cosmosOptions.AccountEndpoint, cosmosOptions.AccountKey, cosmosOptions.DatabaseName);
Now, the SettingsConfiguration doesn't have much in it:
builder.HasKey(x => x.Id).HasName("id");
builder.HasPartitionKey(x => x.Id);
And the Settings look like this:
public class Settings
{
public string Id { get; set; }
public int SomeId { get; private set; }
public string Type { get; private set; }
public int AnotherId { get; private set; }
I've tried querying data from the database, buy everything returns either null or 0 results:
await cosmosContext.Settings.FirstOrDefaultAsync().ConfigureAwait(false); // returns null
await cosmosContext.Settings.CountAsync().ConfigureAwait(false); // returns 0
The connection seems to be fine as there are no exceptions and I did have to make some adjustments in my model because there was some mismatch with the documents.
What could be going wrong?
UPDATE: It appears the HasName() method in the configuration is not working as expected. If I rename the field from "Id" to "id" it works as expected. Looking for a way to properly set the configuration
You should set the key using builder.Property(p => p.Id).ToJsonProperty("id");.
Not sure if it helps, but dont you have to overwrite the OnConfiguring Method?:
public class OptionsContext : DbContext
{
#region Configuration
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.UseCosmos(
"AccountEndpoint=https://localhost:8081/;AccountKey=C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==",
databaseName: "OptionsDB",
options =>
{
options.ConnectionMode(ConnectionMode.Gateway);
options.WebProxy(new WebProxy());
options.LimitToEndpoint();
options.Region(Regions.AustraliaCentral);
options.GatewayModeMaxConnectionLimit(32);
options.MaxRequestsPerTcpConnection(8);
options.MaxTcpConnectionsPerEndpoint(16);
options.IdleTcpConnectionTimeout(TimeSpan.FromMinutes(1));
options.OpenTcpConnectionTimeout(TimeSpan.FromMinutes(1));
options.RequestTimeout(TimeSpan.FromMinutes(1));
});
#endregion
}
Also: Can you create elements in the Db from code?

Can't create database EF Core C#

Im trying to create my database after finnishing up my classes, getting error message
"Unable to create an object of type 'HamsterDbContext'. For the different patterns supported at design time"
public class HamsterDbContext : DbContext
{
public HamsterDbContext(DbContextOptions<HamsterDbContext> options) : base(options) { }
public virtual DbSet<Hamster> Hamsters { get; set; }
public virtual DbSet<Cage> Cages { get; set; }
public virtual DbSet<ExerciseArea> ExerciseArea { get; set; }
}
internal class DatabaseHelper
{
public static HamsterDbContext NewContext()
{
const string host = "(LocalDB)\\MSSQLLocalDB";
const string database = "HamsterDaycare";
var connectionString = $"Data Source={host};Initial Catalog={database};Integrated Security=True;";
var dbContextBuilder = new DbContextOptionsBuilder<HamsterDbContext>();
dbContextBuilder.UseSqlServer(connectionString);
return new HamsterDbContext(dbContextBuilder.Options);
}
}
Looks like this, typing add-migration CreateDatabase, what am i doing wrong here?
Fix your string connection. Instead DataSource, put server. Your ConnectionString must be this way:
{
"ConnectionStrings": {
"DefaultConnection": "server=yourserver;database=yourdatabase;user=youruser;password=yourpassword"},
...
},

MVC 6 Create View issues : There was an error creating the DBContext to get the model

Attempting to create a view for "Create" using the NavBar Model and the NavBarEntity shown below (in MVC6) receives this message...
There was an error running the selected code generator: There was an error creating the DBVContext instance to get the model... Value cannot be null... Parameter Name: connectionString
I picked this mode in View Wizard...
public class NavBarModel
{
public string ID { get; set; }
public List<LinkModel> Links { get; set; }
}
This DBContext class is shown here...
public class NavBarEntity : DbContext
{
public NavBarEntity()
{
ID = Guid.NewGuid().ToString();
}
[Key]
public string ID { get; set; }
public DbSet<List<LinkModel>> Links { get; set; }
}
And the LinkModel shown here..
public class LinkModel
{
public LinkModel()
{
ID = Guid.NewGuid().ToString();
}
[Key]
private string ID { get; set; }
public string HREF { get; set; }
public string Text { get; set; }
}
Configure Services looks like this...
var cfg2 = Configuration["Data Source=MyPC\\SQLEXPRESS;Initial Catalog=Dashboard;Integrated Security=True;Pooling=False"];
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(cfg))
.AddDbContext<NavBarEntity>(options =>
{
options.UseSqlServer(cfg2);
});
Question: What am I doing wrong?
Thanks for the help listed above..
For newbies to MVC6 and EF7, the method named ConfigureServices, must contain a json pointer to the appsetting.json. That method is found in the Startup.cs file.
This is the services configuration to match the code shown above. The string value in the brackets points to the json location...
var cfg2 = Configuration["Data:DashboardContext:ConnectionString"];
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<DashboardContext>(options =>
{
options.UseSqlServer(cfg2);
})
But, you must also put a value into appsettings.json like this:
"Data": {
"DefaultConnection": {
"ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=aspnet5-TestWebApplication1-d91c23e4-3565-476d-a7c0-45665bc0c367;Trusted_Connection=True;MultipleActiveResultSets=true"
},
"DashboardContext": {
"ConnectionString": "Data Source= MYPC\\SQLEXPRESS;Initial Catalog=Dashboard;Integrated Security=True;Pooling=False"
}
},
The root cause of the Parameter Name: connectionString being null was that the appsettings.json has to be exactly as shown above. The json parsing routines must be able to locate the string name/value pair... Notice that these configurations fall under the "Data" name that contains other names. in this case "DefaultConnection" was there by default, and I added "DashboardContext" portion.
Also in MVC 6 you must change the connectionString type to IServiceProvider and NOT string as was done before...
public class DashboardContext : DbContext
{
public DashboardContext(IServiceProvider connectionString) : base (connectionString)
{}
public DbSet<NavBarEntity> NavBars { get; set; }
}
Alas: The Views created no problem...Yes!
The way you've tried to combine the DbContext and your entity isn't right. The DbContext should reference any entities you have as DbSets - entities should not inherit from it.
Your DbContext should look similar to this (EF6)
public class MyDbContext : DbContext
{
public MyDbContext(string connectionString)
: base(connectionString)
{ }
public DbSet<NavBarEntity> NavBars { get; set; }
// Other entities
}
The constructor takes the name of the connecting string entry that's defined in your web.config you want to use. There are other ways to do this though - see here
Then create your entities as a simple class (POCO):
public class NavBarEntity
{
public NavBarEntity()
{
ID = Guid.NewGuid().ToString();
}
[Key]
public string ID { get; set; }
// Other properties/columns here
}
EDIT
My original answer was based on EF6 rather than EF7. Here's how I would implement the context in EF7 for completeness:
public class MyDbContext : DbContext
{
public MyDbContext(DbContextOptions<MyDbContext> options)
: base(options)
{ }
public DbSet<NavBarEntity> NavBars { get; set; }
// Other entities
}

Categories

Resources