Enabling auto migration at an Identity Context - c#

I'm using .NET MVC 5 to create an application. I'm using the code first approach. I have a separated assembly to put my database classes, and have separated my context in different migrations folders. So far I have 2 contexts, and one is the IdentityDb that inherits from IdentityDbContext.
So far, so good. But when I try to enable auto migrations (because I still don't have an production version and an auto migration will not hurt), something bad happens at IdentityDb. This is how I enabled the Auto Migration:
public class IdentityDb : IdentityDbContext<ApplicationUser>
{
public IdentityDb() : base("DefaultConnection")
{
Database.SetInitializer(new MigrateDatabaseToLatestVersion<IdentityDb, Configuration>("DefaultConnection"));
}
}
Of Course I have the Configuration class, with the seed method, and AutomaticMigrationsEnabled property set to true. Everything seems fine, but when I try to do something that needs the Identity context (such as login), I get this error message:
The ConnectionString property has not been initialized
The line it says there is the error is at:
public IdentityDb() : base("DefaultConnection")
But it is. I assume that when I pass it as "DefaultConnection" at the base constructor and when instantiating the MigrateDatabaseToLatestVersion, the connection string is set.
Finally, I want to say that this only happen at IdentityDb context. I have auto migrations enabled in my other context, CampaignsDb, exactly the same way, and it works perfectly. Does anyone have an idea about what's happening with the IdentityDb? Is the problem because this class inherits the IdentityDbContext, and the auto migrations should be enabled with a different approach?

remove the "DefaultConnection" from MigrateDatabaseToLatestVersion. You already have your configuration type passed in, which in turn should be using your DBContext. So it would be like this:
Database.SetInitializer(new MigrateDatabaseToLatestVersion<IdentityDb, Configuration>());

Related

Change Id type of asp.net core 2.2 IdentityUser

I'm new to dot-net core 2.x, so...
I would like to change the type of the Id in asp.net core 2.2 IdentityUser from string to int.
All the examples I've found via google (and the stackoverflow search facility) are giving me examples of asp.net core 2.0 which provides an ApplicationUser when you scaffold Identity (which 2.2 did not provide).
SO, I'm at a loss.. The first thing I tried (which I had high hopes for) was:
services.AddDefaultIdentity<IdentityUser<int>>()
.AddRoles<IdentityRole>()
.AddDefaultTokenProviders()
.AddEntityFrameworkStores<ApplicationDbContext>();
But, I get the following error when I try to Add-Migration InitialCreate -Context ApplicationDbContext:
An error occurred while accessing the IWebHost on class 'Program'. Continuing without the application service provider. Error: GenericArguments[0], 'Microsoft.AspNetCore.Identity.IdentityUser`1[System.Int32]', on 'Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore`9[TUser,TRole,TContext,TKey,TUserClaim,TUserRole,TUserLogin,TUserToken,TRoleClaim]' violates the constraint of type 'TUser'
Thoughts? Ideas? Documentation I can read?
For changing IdentityUser key type from string to int, you also need to change the IdentityDbContext to IdentityDbContext<IdentityUser<int>,IdentityRole<int>,int>.
Startup.cs
services.AddDefaultIdentity<IdentityUser<int>>()
.AddDefaultUI(UIFramework.Bootstrap4)
.AddEntityFrameworkStores<ApplicationDbContext>();
ApplicationDbContext
public class ApplicationDbContext : IdentityDbContext<IdentityUser<int>,IdentityRole<int>,int>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
}
Remove Migrations folder and delete the existing database
Run command to add and update the database
You can write your own implementation that derives from IdentityUser
public class AppUser : IdentityUser<int>
{
}
Then register it:
services.AddDefaultIdentity<AppUser>()
This is also useful if you want to add additional properties to your user model.
Remember that because you are changing primary key of the tables, so you will need to recreate these tables instead of updating them.

Moving Entity framework to another project from MVC causes re-migration

I currently have an asp.net MVC 4 application which contains Entity framework 6 Code First models, DbContext and Migrations. In an attempt to separate this from my web application so I can re-use these database classes in another project I have moved all related Entity Framework classes to their own project.
However now when I run the solution it thinks my model has changed and attempts to run all my migrations once more. The problem appears to be in my use of SetInitializer as if I comment out this line I can run the web application as per normal.
public static class DatabaseConfig
{
public static void Initialize()
{
System.Data.Entity.Database.SetInitializer(new MigrateDatabaseToLatestVersion<G5DataContext, Configuration>());
// make sure the database is created before SimpleMembership is initialised
using (var db = new G5DataContext())
db.Database.Initialize(true);
}
}
This wasn't a problem until I've tried to move all the Entity Framework classes. Is this not possible, or have I done something fundamentally wrong?
At startup, EF6 queries exiting migrations in your database, as stored in the __MigrationHistory table. Part of this table is a context key, which includes the namespace of the entities.
If you move everything to a new namespace, EF6 doesn't recognize any of the previously run migrations, and tries to rebuild the database.
A quick solution is to run a script to rename the context key in the __MigrationHistory table to your new namespace. From http://jameschambers.com/2014/02/changing-the-namespace-with-entity-framework-6-0-code-first-databases/ :
UPDATE [dbo].[__MigrationHistory]
SET [ContextKey] = 'New_Namespace.Migrations.Configuration'
WHERE [ContextKey] = 'Old_Namespace.Migrations.Configuration'
Would also like to add that you should remember to change the ContextKey property in your Configuration class. I did the above but it was still trying to create a new database. Here's an example:
Before:
internal sealed class Configuration : DbMigrationsConfiguration<PricedNotesContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
ContextKey = "Synapse.DAL.PricedNotesContext";
}
protected override void Seed(PricedNotesContext context)
{
}
}
After:
internal sealed class Configuration : DbMigrationsConfiguration<PricedNotesContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
ContextKey = "SynapseDomain.DAL.PricedNotesContext";
}
protected override void Seed(PricedNotesContext context)
{
}
}
Hope this helps anyone who is stuck on this. It's a shame that it shouldn't be easier...

Does IdentityDbContext always need a DefaultConnection

I was working at an asp.net MVC project with the IdentityDbContext.
The code for the context:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("ApplicationDb")
{
}
}
And in my web.config a connectionstring named after the context:
<add name="ApplicationDb" connectionString="Data Source="..." providerName="System.Data.SqlClient" />
Strange thing is when I call the Update-Database command to create the database with Entity Framework, my database is created. So far so good.
But: the authorisation code from Owin is also creating a second upon running the application. This one is named DefaultConnection and is copy from the other one.
So my question: does Identity Framework always need a connection string named "DefaultConnection", even if you point the context to another connectionstring?
In the end I managed to solve this by adding the DefaultConnection connectionstring in web.config so I end up with two connectionstring:
ApplicationDb
DefaultConnection
Is this really the way to go? Because if that's the case it doesn't make much sense to put a custom connectionstring name in the base constructor?!
Btw, I also tried the context like so:
public ApplicationDbContext()
{
}
Which in theory should effectively do the same. But still DefaultConnection is created upon running the app. Doesn't make sense to me.

The model backing the 'ApplicationDbContext' context has changed since the database was created When upload project to server

why i find this error:
The model backing the 'ApplicationDbContext' context has changed since the database was created. This could have happened because the model used by ASP.NET Identity Framework has changed or the model being used in your application has changed. To resolve this issue, you need to update your database. Consider using Code First Migrations to update the database (http://go.microsoft.com/fwlink/?LinkId=301867). Before you update your database using Code First Migrations, please disable the schema consistency check for ASP.NET Identity by setting throwIfV1Schema = false in the constructor of your ApplicationDbContext in your application.
public ApplicationDbContext() : base("ApplicationServices", throwIfV1Schema:false)
this error happens when i upload project to the server also it working good in local.
my application context code is:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection",throwIfV1Schema : false)
{
}
}
Knowing i'm add this code in AppStart{}
Database.SetInitializer<ApplicationDbContext>(null);

EF6 and multiple configurations (SQL Server and SQL Server Compact)

Update: Problem solved, see end of this question.
The problem:
We are trying to use Entity Framework 6 and code-based configuration in a scenario were we have use both a SQL Server and SQL Server CE in the same AppDomain.
This quite simple scenario seems not to be supported "by design". From the EF team:
Note: We do not support having multiple configuration classes used in
the same AppDomain. If you use this attribute to set different
configuration classes for two contexts an exception will be thrown.
More information here: Code-based Configuration (Codeplex)
The question:
How do we move forward from here? Any help would be greatly appreciated! Is there a more flexible way to connect a configuration to a context instead of an AppDomain?
(Our context classes are located in different assemblies. We have tried the DbConfigurationType attribute but the problem is EF itself)
Configuration files:
Configuration for normal SQL server
public class EfConfiguration : DbConfiguration
{
public EfConfiguration()
{
SetProviderServices(
SqlProviderServices.ProviderInvariantName,
SqlProviderServices.Instance);
SetDefaultConnectionFactory(new SqlConnectionFactory());
}
}
Configuration for SQL Server Compact Edition
public class EfCeConfiguration : DbConfiguration
{
public EfCeConfiguration()
{
SetProviderServices(
SqlCeProviderServices.ProviderInvariantName,
SqlCeProviderServices.Instance);
SetDefaultConnectionFactory(
new SqlCeConnectionFactory(SqlCeProviderServices.ProviderInvariantName));
}
}
UPDATE:
The error which we get is:
System.TypeInitializationException : The type initializer for
'MyProject.Repositories.Base.DataContext'
threw an exception. ----> System.InvalidOperationException : An
instance of 'EfCeConfiguration' was set but this type was not
discovered in the same assembly as the 'DataContext' context. Either
put the DbConfiguration type in the same assembly as the DbContext
type, use DbConfigurationTypeAttribute on the DbContext type to
specify the DbConfiguration type, or set the DbConfiguration type in
the config file. See http://go.microsoft.com/fwlink/?LinkId=260883 for
more information.
UPDATE 2, the solution
As described above, we can only have one configuration. This is a problem since Sql and SqlCe uses different providers. If we use "SetDefaultConnectionFactory" to fit one type of database, the other will fail.
Instead, supply the connection into the context as described in the post marked as answer below. Once you always initialize the context with a connection as opposed to a connectionstring you are good to go. You can remove the SetDefaultConnectionFactory call from the configuration. We're using only the code below for configuring the SqlCe Context and no configuration for the Sql Context.
public class CommonEfConfiguration : DbConfiguration
{
public CommonEfConfiguration()
{
// EF does not know if the ce provider by default,
// therefore it is required to be informed about it.
// The connection factories are not necessary since the connection
// is always created in the UnitOfWork classes
SetProviderServices(SqlCeProviderServices.ProviderInvariantName, SqlCeProviderServices.Instance);
}
}
EDIT: based On Error details:
Did you already try tell EF where the config class is found?
[DbConfigurationType("MyNamespace.MyDbConfiguration, MyAssemblyFullyQualifiedName")]
public class MyContextContext : DbContext
{
}
If that cant be made work, then see alternative
Use the Context with constructor DbConnection
public class MYDbContext : DbContext {
// MIgration parameterless constructor is managed in MyMigrationsContextFactory
public MyDbContext(string connectionName) : base(connectionName) { } // no this
public MYDbContext(DbConnection dbConnection, bool contextOwnsConnection) // THIS ONE
: base(dbConnection, contextOwnsConnection) { }
you then need a "DBConnection" connection for each provider.
For SQL server
public DbConnection GetSqlConn4DbName(string dataSource, string dbName) {
var sqlConnStringBuilder = new SqlConnectionStringBuilder();
sqlConnStringBuilder.DataSource = String.IsNullOrEmpty(dataSource) ? DefaultDataSource : dataSource;
sqlConnStringBuilder.IntegratedSecurity = true;
sqlConnStringBuilder.MultipleActiveResultSets = true;
var sqlConnFact = new SqlConnectionFactory(sqlConnStringBuilder.ConnectionString);
var sqlConn = sqlConnFact.CreateConnection(dbName);
return sqlConn;
}
repeat for SqlCe factory, it can also generate a DBConnection
SqlCe connection factor create connection
what i did:
public partial class MyDataBaseContext : DbContext
{
public MyDataBaseContext (string ConnectionString)
: base(ConnectionString)
{
}
}
I found the solution in a post on a Microsoft forum post.
Basically, I had two projects, each one with its own context. Entity Framework was loading just (the first) one of the DbConfiguration classes and trying to use this same configuration for both projects. That's the reason for the error message saying something like
"An instance of 'EfCeConfiguration' was set but this type was not discovered in the same assembly as the 'DataContext' context".
So, as someone suggested in that Microsoft forum post, I removed all [DbConfigurationType(typeof(DbConfigurationClass))] anotations from the classes which inherit from DbContext in both projects, and the error didn't happen anymore.

Categories

Resources