Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Scaffolding doesn't work when DbContext is in a separate project #1765

Open
signumq opened this issue Dec 22, 2021 · 31 comments
Open

Scaffolding doesn't work when DbContext is in a separate project #1765

signumq opened this issue Dec 22, 2021 · 31 comments

Comments

@signumq
Copy link

signumq commented Dec 22, 2021

Consistently getting this error when attempting to scaffold a controller while having DbContext in a separate project:

There was an error running selected code generator:

'Unable to resolve service for type 
'Microsoft.EntityFrameworkCore.DbContextOptions`1[MyProject.Data.MyProjectDbContext]' 
while attempting to activate 'MyProject.Data.MyProjectDbContext'.'

MyProjectDbContext:

public class MyProjectDbContext : DbContext
{
    public MyProjectDbContext(DbContextOptions<MyProjectDbContext> options) : base (options)
    { }

    public DbSet<Note> Notes => Set<Note>();
}

DbContext is registered in Program.cs as follows:

builder.Services.AddDbContext<MyProjectDbContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("MyProjectDbContext")));

Scaffolding works if DbContext moved to the web project.

IDE: Visual Studio 2022 Community
SDK: .NET 6.0
Packages:
"Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="6.0.1"
"Microsoft.EntityFrameworkCore.Tools" Version="6.0.1"
"Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.1"

@signumq signumq changed the title Scaffolding doesn't work when DbContext is in separate project Scaffolding doesn't work when DbContext is in a separate project Dec 22, 2021
@nitsujT
Copy link

nitsujT commented Feb 20, 2022

Did you find a solution? I'm having the same issue.

The migrations are working fine, but Scaffolding wont work. Only slight difference is I am using IdentityDbContext.

@iannicktl
Copy link

Same issue here . But with Version 6.02

@mjohn
Copy link

mjohn commented Mar 3, 2022

Same here.

@cemg
Copy link

cemg commented Mar 3, 2022

I found a solution.
You can create a dbcontext factory class in same folder with your ApplicationDbContext class.
This factory class creates ApplicationDbContext at design time and scaffolding runs correctly.

public class ApplicationDbContextFactory : IDesignTimeDbContextFactory<ApplicationDbContext>
{
        public ApplicationDbContext CreateDbContext(string[] args)
        {
            var optionsBuilder = new DbContextOptionsBuilder<ApplicationDbContext>();
            optionsBuilder.UseSqlServer("Server=(localdb)\\MSSQLLocalDB;Database=EcommerceDb;Trusted_Connection=True;MultipleActiveResultSets=true");

            return new ApplicationDbContext(optionsBuilder.Options);
        }
}

IDE: VS 2022 Pro
Framework: .NET6
Packages Version: 6.0.2

@mjohn
Copy link

mjohn commented Mar 4, 2022

I found a solution. You can create a dbcontext factory class in same folder with your ApplicationDbContext class. This factory class creates ApplicationDbContext at design time and scaffolding runs correctly.

public class ApplicationDbContextFactory : IDesignTimeDbContextFactory<ApplicationDbContext>
{
        public ApplicationDbContext CreateDbContext(string[] args)
        {
            var optionsBuilder = new DbContextOptionsBuilder<ApplicationDbContext>();
            optionsBuilder.UseSqlServer("Server=(localdb)\\MSSQLLocalDB;Database=EcommerceDb;Trusted_Connection=True;MultipleActiveResultSets=true");

            return new ApplicationDbContext(optionsBuilder.Options);
        }
}

IDE: VS 2022 Pro Framework: .NET6 Packages Version:

Thanks Cem, nice workaround though, its working!
Teşekkürler.

@nitsujT
Copy link

nitsujT commented Mar 4, 2022

@cemg Thanks! This also works for me.

@avinashtauro-arctechinfo

Thanks @cemg. Found this after hours of testing. Works great

@farazymaxit2021
Copy link

thanks for the solution

@d99mli
Copy link

d99mli commented May 10, 2022

Had the same issue, with scaffolding an api controller. This did the trick, THANKS!

@signumq
Copy link
Author

signumq commented May 20, 2022

This solution works, thank you!
But how do I pass connection string to it from configuration? It wants to use parameterless constructor, so I can't inject IConfiguration.

@cemg
Copy link

cemg commented May 20, 2022

You can use ConfigurationBuilder class for build the configuration.

public class ApplicationDbContextFactory : IDesignTimeDbContextFactory<ApplicationDbContext>
{
    public ApplicationDbContext CreateDbContext(string[] args)
    {
        var configuration = new ConfigurationBuilder()
            .SetBasePath(AppDomain.CurrentDomain.BaseDirectory)
            .AddJsonFile("appsettings.json")
            .Build();
        
        var optionsBuilder = new DbContextOptionsBuilder<ApplicationDbContext>();
        optionsBuilder.UseSqlServer(configuration.GetConnectionString("Default"));

        return new ApplicationDbContext(optionsBuilder.Options);
    }
}

@JuliusJacobsohn
Copy link

JuliusJacobsohn commented Jun 23, 2022

I found a solution. You can create a dbcontext factory class in same folder with your ApplicationDbContext class. This factory class creates ApplicationDbContext at design time and scaffolding runs correctly.

public class ApplicationDbContextFactory : IDesignTimeDbContextFactory<ApplicationDbContext>
{
        public ApplicationDbContext CreateDbContext(string[] args)
        {
            var optionsBuilder = new DbContextOptionsBuilder<ApplicationDbContext>();
            optionsBuilder.UseSqlServer("Server=(localdb)\\MSSQLLocalDB;Database=EcommerceDb;Trusted_Connection=True;MultipleActiveResultSets=true");

            return new ApplicationDbContext(optionsBuilder.Options);
        }
}

IDE: VS 2022 Pro Framework: .NET6 Packages Version: 6.0.2

Although this resolved the issue for me, it introduced some side effects which I only realized weeks later. It changes some of the internals of identity classes, see the following migration:

            migrationBuilder.AlterColumn<string>(
                name: "Name",
                table: "AspNetUserTokens",
                type: "nvarchar(450)",
                nullable: false,
                oldClrType: typeof(string),
                oldType: "nvarchar(128)",
                oldMaxLength: 128);

            migrationBuilder.AlterColumn<string>(
                name: "LoginProvider",
                table: "AspNetUserTokens",
                type: "nvarchar(450)",
                nullable: false,
                oldClrType: typeof(string),
                oldType: "nvarchar(128)",
                oldMaxLength: 128);

            migrationBuilder.AlterColumn<string>(
                name: "ProviderKey",
                table: "AspNetUserLogins",
                type: "nvarchar(450)",
                nullable: false,
                oldClrType: typeof(string),
                oldType: "nvarchar(128)",
                oldMaxLength: 128);

            migrationBuilder.AlterColumn<string>(
                name: "LoginProvider",
                table: "AspNetUserLogins",
                type: "nvarchar(450)",
                nullable: false,
                oldClrType: typeof(string),
                oldType: "nvarchar(128)",
                oldMaxLength: 128);

Even though nothing else was changed in the project (related to the database schema), when your proposed class is present, these columns are changed when trying to create a new migration. Removing the class and rescaffolding the migration results in an empty migration.

Setting the MaxLengthForKeys property manually in the relevant Program.cs (as mentioned here) changes nothing.

Not sure where this comes from but maybe this is useful information to someone.

@ataccounts
Copy link

Worked on first try. Thanks!

@FaouziSelmi
Copy link

thanks bro

@aftabalamans
Copy link

configuration 

Not working at my end getting same issue

Microsoft Visual Studio Community 2022 (64-bit) - Preview
Version 17.4.0 Preview 2.1

TargetFramework net7.0
Microsoft.VisualStudio.Web.CodeGeneration.Design, Version=7.0.0-rc.1.22452.2

@rafaoliveira4
Copy link

@cemg Thanks! This work for me.

@awdorrin
Copy link

awdorrin commented Nov 15, 2022

Ipublic class ApplicationDbContextFactory : IDesignTimeDbContextFactory<ApplicationDbContext>
{
    public ApplicationDbContext CreateDbContext(string[] args)
    {
        var configuration = new ConfigurationBuilder()
            .SetBasePath(AppDomain.CurrentDomain.BaseDirectory)
            .AddJsonFile("appsettings.json")
            .Build();
        
        var optionsBuilder = new DbContextOptionsBuilder<ApplicationDbContext>();
        optionsBuilder.UseSqlServer(configuration.GetConnectionString("Default"));

        return new ApplicationDbContext(optionsBuilder.Options);
    }
}

Issue with this approach is that it doesn't consider environment (Development/Staging/Production) for the appsettings.{env}.json.

@HagenKnight
Copy link

configuration.GetConnectionString("Default")

It was useful for me but the SetBasePath method throwed me an error. I fix it adding two nugget packages:

Microsoft.Extensions.Configuration.FileExtensions
Microsoft.Extensions.Configuration.Json

The answer was commented on:
https://stackoverflow.com/questions/36001695/setting-base-path-using-configurationbuilder

@mhasz
Copy link

mhasz commented Feb 7, 2023

Eu encontrei uma solução. Você pode criar uma classe de fábrica dbcontext na mesma pasta com sua classe ApplicationDbContext. Essa classe de fábrica cria ApplicationDbContext em tempo de design e o scaffolding é executado corretamente.

public class ApplicationDbContextFactory : IDesignTimeDbContextFactory<ApplicationDbContext>
{
        public ApplicationDbContext CreateDbContext(string[] args)
        {
            var optionsBuilder = new DbContextOptionsBuilder<ApplicationDbContext>();
            optionsBuilder.UseSqlServer("Server=(localdb)\\MSSQLLocalDB;Database=EcommerceDb;Trusted_Connection=True;MultipleActiveResultSets=true");

            return new ApplicationDbContext(optionsBuilder.Options);
        }
}

IDE: VS 2022 Pro Framework: Pacotes .NET6 Versão: 6.0.2

Embora isso tenha resolvido o problema para mim, introduziu alguns efeitos colaterais que só percebi semanas depois. Ele altera algumas das partes internas das classes de identidade, consulte a migração a seguir:

            migrationBuilder.AlterColumn<string>(
                name: "Name",
                table: "AspNetUserTokens",
                type: "nvarchar(450)",
                nullable: false,
                oldClrType: typeof(string),
                oldType: "nvarchar(128)",
                oldMaxLength: 128);

            migrationBuilder.AlterColumn<string>(
                name: "LoginProvider",
                table: "AspNetUserTokens",
                type: "nvarchar(450)",
                nullable: false,
                oldClrType: typeof(string),
                oldType: "nvarchar(128)",
                oldMaxLength: 128);

            migrationBuilder.AlterColumn<string>(
                name: "ProviderKey",
                table: "AspNetUserLogins",
                type: "nvarchar(450)",
                nullable: false,
                oldClrType: typeof(string),
                oldType: "nvarchar(128)",
                oldMaxLength: 128);

            migrationBuilder.AlterColumn<string>(
                name: "LoginProvider",
                table: "AspNetUserLogins",
                type: "nvarchar(450)",
                nullable: false,
                oldClrType: typeof(string),
                oldType: "nvarchar(128)",
                oldMaxLength: 128);

Mesmo que nada mais tenha sido alterado no projeto (relacionado ao esquema do banco de dados), quando sua classe proposta está presente, essas colunas são alteradas ao tentar criar uma nova migração. Remover a classe e reestruturar a migração resulta em uma migração vazia.

Definir a MaxLengthForKeyspropriedade manualmente no relevante Program.cs(como mencionado aqui ) não altera nada.

Não tenho certeza de onde isso vem, mas talvez seja uma informação útil para alguém.

I believe that your problem has come from elsewhere, microsoft itself recommends building a db context factory.

@ahaque98
Copy link

ahaque98 commented Feb 9, 2023

I found a solution. You can create a dbcontext factory class in same folder with your ApplicationDbContext class. This factory class creates ApplicationDbContext at design time and scaffolding runs correctly.

public class ApplicationDbContextFactory : IDesignTimeDbContextFactory<ApplicationDbContext>
{
        public ApplicationDbContext CreateDbContext(string[] args)
        {
            var optionsBuilder = new DbContextOptionsBuilder<ApplicationDbContext>();
            optionsBuilder.UseSqlServer("Server=(localdb)\\MSSQLLocalDB;Database=EcommerceDb;Trusted_Connection=True;MultipleActiveResultSets=true");

            return new ApplicationDbContext(optionsBuilder.Options);
        }
}

IDE: VS 2022 Pro Framework: .NET6 Packages Version: 6.0.2

Thanks. Worked like a charm!

@VladDerptastic
Copy link

I found a solution. You can create a dbcontext factory class in same folder with your ApplicationDbContext class. This factory class creates ApplicationDbContext at design time and scaffolding runs correctly.

public class ApplicationDbContextFactory : IDesignTimeDbContextFactory<ApplicationDbContext>
{
        public ApplicationDbContext CreateDbContext(string[] args)
        {
            var optionsBuilder = new DbContextOptionsBuilder<ApplicationDbContext>();
            optionsBuilder.UseSqlServer("Server=(localdb)\\MSSQLLocalDB;Database=EcommerceDb;Trusted_Connection=True;MultipleActiveResultSets=true");

            return new ApplicationDbContext(optionsBuilder.Options);
        }
}

IDE: VS 2022 Pro Framework: .NET6 Packages Version: 6.0.2

Does this also apply when referencing a different DBContext?
I've created 2 factory classes - one for the ApplicationDbContext, and one for [MyOwnDBContext] which is in another project (but referenced in its factory of course) and placed them in the same folder with ApplicationDbContext.cs and the problem still persists. I've tried with only one or the other, and that still doesn't help. I'm a bit stuck, honestly.

@arezaie9331
Copy link

arezaie9331 commented Mar 18, 2023

I found a solution. You can create a dbcontext factory class in same folder with your ApplicationDbContext class. This factory class creates ApplicationDbContext at design time and scaffolding runs correctly.

public class ApplicationDbContextFactory : IDesignTimeDbContextFactory<ApplicationDbContext>
{
        public ApplicationDbContext CreateDbContext(string[] args)
        {
            var optionsBuilder = new DbContextOptionsBuilder<ApplicationDbContext>();
            optionsBuilder.UseSqlServer("Server=(localdb)\\MSSQLLocalDB;Database=EcommerceDb;Trusted_Connection=True;MultipleActiveResultSets=true");

            return new ApplicationDbContext(optionsBuilder.Options);
        }
}

IDE: VS 2022 Pro Framework: .NET6 Packages Version: 6.0.2

Is Also works for me . thx❤️

@ghhv
Copy link

ghhv commented Apr 4, 2023

This doesn't work as shown with .NET 7.. You now need to add new package references. See this page - https://learn.microsoft.com/en-us/dotnet/core/extensions/configuration#basic-example

@hamzabourkha
Copy link

This doesn't work as shown with .NET 7.. You now need to add new package references. See this page - https://learn.microsoft.com/en-us/dotnet/core/extensions/configuration#basic-example

it works for me in .NET 7

@tiennsloit
Copy link

I found a solution. You can create a dbcontext factory class in same folder with your ApplicationDbContext class. This factory class creates ApplicationDbContext at design time and scaffolding runs correctly.

public class ApplicationDbContextFactory : IDesignTimeDbContextFactory<ApplicationDbContext>
{
        public ApplicationDbContext CreateDbContext(string[] args)
        {
            var optionsBuilder = new DbContextOptionsBuilder<ApplicationDbContext>();
            optionsBuilder.UseSqlServer("Server=(localdb)\\MSSQLLocalDB;Database=EcommerceDb;Trusted_Connection=True;MultipleActiveResultSets=true");

            return new ApplicationDbContext(optionsBuilder.Options);
        }
}

IDE: VS 2022 Pro Framework: .NET6 Packages Version: 6.0.2

Awesome! Thanks cemg. It works for me.

@kdenaeem
Copy link

Hey @cemg
Im having a similar issue with creating a Scaffolding item. Im trying to create a MVC controller with views, using Entity framework on an example application. I've followed this video step by step but Im stuck at creating this controller
https://www.youtube.com/watch?v=BfEjDD8mWYg
image
I have my project on github, if you could have a look at the repo you'll see the exact same structure as my project.
image
Thats the error I'm having.

Thanks

@nezoic
Copy link

nezoic commented Oct 30, 2023

Is there a more concrete solution to this? Creating a temporary factory feels pretty janky. It's been several years, lets FIX the tool instead of work around it.

@uehlbran
Copy link

Is there a more concrete solution to this? Creating a temporary factory feels pretty janky. It's been several years, lets FIX the tool instead of work around it.

I have to agree. It's absolutely absurd that a workaround is required for what has to be one of the most common scenarios in using ef core.

@svrooij
Copy link

svrooij commented Nov 24, 2023

I found a solution. You can create a dbcontext factory class in same folder with your ApplicationDbContext class. This factory class creates ApplicationDbContext at design time and scaffolding runs correctly.

public class ApplicationDbContextFactory : IDesignTimeDbContextFactory<ApplicationDbContext>
{
        public ApplicationDbContext CreateDbContext(string[] args)
        {
            var optionsBuilder = new DbContextOptionsBuilder<ApplicationDbContext>();
            optionsBuilder.UseSqlServer("Server=(localdb)\\MSSQLLocalDB;Database=EcommerceDb;Trusted_Connection=True;MultipleActiveResultSets=true");

            return new ApplicationDbContext(optionsBuilder.Options);
        }
}

IDE: VS 2022 Pro Framework: .NET6 Packages Version: 6.0.2

I cannot believe this incredible simple solution is not in the official documentation, @cemg thank you for this!!

HansRisberg pushed a commit to HansRisberg/GameReviewer-WebApp that referenced this issue Feb 19, 2024
Solution was adding a dbcontextfactory.
dotnet/Scaffolding#1765
@1a2e1
Copy link

1a2e1 commented Feb 27, 2024

you saved us cemg

I was considering creating everything by hand, but it seems that divine intervention has sent you to help us.
AI helps to Update my gratitude: "i was thinking about creating it all by hands, but divine itself send you for us".

Thanks a lot

@JordanCampos20
Copy link

I found a solution. You can create a dbcontext factory class in same folder with your ApplicationDbContext class. This factory class creates ApplicationDbContext at design time and scaffolding runs correctly.

public class ApplicationDbContextFactory : IDesignTimeDbContextFactory<ApplicationDbContext>
{
        public ApplicationDbContext CreateDbContext(string[] args)
        {
            var optionsBuilder = new DbContextOptionsBuilder<ApplicationDbContext>();
            optionsBuilder.UseSqlServer("Server=(localdb)\\MSSQLLocalDB;Database=EcommerceDb;Trusted_Connection=True;MultipleActiveResultSets=true");

            return new ApplicationDbContext(optionsBuilder.Options);
        }
}

IDE: VS 2022 Pro Framework: .NET6 Packages Version: 6.0.2

Thank you very much, this saved my creation of razor pages with entity framework

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests