dotnet / efcore

EF Core is a modern object-database mapper for .NET. It supports LINQ queries, change tracking, updates, and schema migrations.
https://docs.microsoft.com/ef/
MIT License
13.78k stars 3.19k forks source link

Design: Startup.ConfigureServices not invoked #7237

Closed Defee closed 2 years ago

Defee commented 7 years ago

Issue: Run the migrations with the contexts located in the packages.

I have a web project. I also have many separate DbContexts. I want my web project to manage contexts. So, I want to store migrations in the web project. And contexts

After I ran the dotnet ef dbcontext list,I have following contexts listed: odec.Server.Model.Auction.Contexts.AuctionContext odec.Server.Model.OrderProcessing.Contexts.EntireMoneyProcessingContext odec.Server.Model.OrderProcessing.Contexts.OrderContext odec.Server.Model.Work.Contexts.WorkContext odec.CP.Server.Model.User.Membership.Simple.Contexts.UserContextExt odec.Server.Model.Personal.Store.Contexts.PersonalStoreContext odec.Server.Model.Store.Contexts.Blob.StoreContext

But i have the issue running following command: dotnet ef migrations add 'WorkInitial'-c 'odec.Server.Model.Work.Contexts.WorkContext' -o .\Data\Migrations\Work --verbose It results in the exception below (the context has required things, so, I don't know what is that about). Below is complete listing. Please, help to figure out what is wrong.

PS output

Exception message:
Stack trace:
``[ERROR] System.InvalidOperationException: No database provider has been configured for this DbContext. A provider can be configured by overriding the 
[ERROR] DbContext.OnConfiguring method or by using AddDbContext on the application service provider. If AddDbContext is us
[ERROR] ed, then also ensure that your DbContext type accepts a DbContextOptions<TContext> object in its constructor and passes it to the base constructor for 
[ERROR] DbContext.
[ERROR]    at Microsoft.EntityFrameworkCore.Internal.DatabaseProviderSelector.SelectServices()
[ERROR]    at Microsoft.EntityFrameworkCore.Internal.LazyRef`1.get_Value()
[ERROR]    at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScoped(ScopedCallSite scopedCallSite, ServiceProvider provider)
[ERROR]    at Microsoft.Extensions.DependencyInjection.ServiceProvider.<>c__DisplayClass16_0.<RealizeService>b__0(ServiceProvider provider)
[ERROR] 
[ERROR]    at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
[ERROR] 
[ERROR]    at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
[ERROR] 
[ERROR]    at Microsoft.EntityFrameworkCore.Design.Internal.DesignTimeServicesBuilder.Build(DbContext context)
[ERROR] 
[ERROR] 
[ERROR]    at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.AddMigration(String name, String outputDir, String contextType)
[ERROR] 
[ERROR]    at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigrationImpl(String name, String outputDir, String contextType)
[ERROR]    at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_0`1.<Execute>b__0()
[ERROR] 
[ERROR]    at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
[ERROR] 
[ERROR] No database provider has been configured for this DbContext. A provider can be configured by overriding the DbContext.OnConfiguring method or by using 
[ERROR] AddDbContext on the application service provider. If AddDbContext is used, then also ensure that your DbC
[ERROR] ontext type accepts a DbContextOptions<TContext> object in its constructor and passes it to the base constructor for DbContext.
[ERROR] `

Project Json

{
    "userSecretsId": "***",

"dependencies": {
        "Microsoft.NETCore.App": {
            "version": "1.1.0",
            "type": "platform"
        },
        "Microsoft.AspNetCore.Authentication.Cookies": "1.1.0",
        "Microsoft.AspNetCore.Diagnostics": "1.1.0",
        "Microsoft.AspNetCore.Mvc": "1.1.0",
        "Microsoft.AspNetCore.Razor.Tools": {
            "version": "1.1.0-preview4-final",
            "type": "build"
        },
        "Microsoft.AspNetCore.Routing": "1.1.0",
        "Microsoft.AspNetCore.Server.IISIntegration": "1.1.0",
        "Microsoft.AspNetCore.Server.Kestrel": "1.1.0",
        "Microsoft.AspNetCore.StaticFiles": "1.1.0",
        "Microsoft.EntityFrameworkCore.SqlServer": "1.1.0",
        "Microsoft.EntityFrameworkCore.SqlServer.Design": {
            "version": "1.1.0",
            "type": "build"
        },
        "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.1.0",
        "Microsoft.Extensions.Configuration.Json": "1.1.0",
        "Microsoft.Extensions.Configuration.UserSecrets": "1.1.0",
        "Microsoft.Extensions.Logging": "1.1.0",
        "Microsoft.Extensions.Logging.Console": "1.1.0",
        "Microsoft.Extensions.Logging.Debug": "1.1.0",
        "Microsoft.Extensions.Options.ConfigurationExtensions": "1.1.0",
        "Microsoft.VisualStudio.Web.BrowserLink.Loader": "14.1.0",
        "Microsoft.VisualStudio.Web.CodeGeneration.Tools": {
            "version": "1.1.0-preview4-final",
            "type": "build"
        },
        "Microsoft.VisualStudio.Web.CodeGenerators.Mvc": {
            "version": "1.1.0-preview4-final",
            "type": "build"
        },
        "Autofac": "4.2.0",
        "Autofac.Extensions.DependencyInjection": "4.0.0",
        "Autofac.Configuration": "4.0.1",
        "odec.CP.Server.Model.Contact": "1.0.1-beta184",
        "Lovart.View.Model": "1.0.0-*",
        "Common.Resources": "1.0.0-*",
        "Lovart.Constraints": "1.0.0-*",
        "Lovart.Resources": "1.0.0-*",
        "odec.CP.Auction.DAL": "1.0.1-beta184",
        "odec.CP.Attachment.DAL": "1.0.1-beta184",
        "odec.CP.Conversation.DAL": "1.0.1-beta184",
        "odec.CP.Category.DAL": "1.0.1-beta184",
        "odec.CP.Personal.Store.DAL": "1.0.1-beta184",
        "odec.CP.Work.DAL": "1.0.1-beta184",
        "odec.CP.User.DAL": "1.0.1-beta184",
        "odec.CP.User.Membership.DAL": "1.0.1-beta184",
        "odec.CP.Processing.DAL": "1.0.1-beta184",
        "odec.CP.Server.Model.Location": "1.0.1-beta184",
        "odec.CP.Server.Model.User.Membership": "1.0.1-beta184",
        "BundlerMinifier.Core": "2.2.306",
        "Microsoft.ApplicationInsights.AspNetCore": "1.0.2",
        "odec.CP.Server.Model.Attachment": "1.0.1-beta184",
        "Microsoft.Extensions.SecretManager.Tools": {
            "version": "1.1.0-preview4-final",
            "type": "build"
        },
        "Microsoft.AspNetCore.Server.IISIntegration.Tools": {
            "version": "1.1.0-preview4-final",
            "type": "build"
        },
        "Microsoft.EntityFrameworkCore.Tools": {
            "version": "1.1.0-preview4-final",
            "type": "build"
        }
    },

    "tools": {
        "Microsoft.AspNetCore.Razor.Tools": "1.1.0-preview4-final",
        "Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.1.0-preview4-final",

        "Microsoft.Extensions.SecretManager.Tools": "1.1.0-preview4-final",
        //"Microsoft.EntityFrameworkCore.Tools": "1.0.0-preview4-final",
        "Microsoft.EntityFrameworkCore.Tools.DotNet": "1.0.0-preview3-final",
        "Microsoft.VisualStudio.Web.CodeGeneration.Tools": {
            "version": "1.1.0-preview4-final",
            "imports": [
                "portable-net45+win8"
            ]
        }
    },
    "devDependencies": {
        "gulp": "3.8.11",
        "gulp-concat": "2.5.2",
        "gulp-cssmin": "0.1.7",
        "gulp-uglify": "1.2.0",
        "rimraf": "2.2.8"
    },
    "frameworks": {
        "netcoreapp1.0": {
            "imports": [
                "dotnet5.6",
                "portable-net45+win8"
            ]
        }
    },

    "buildOptions": {
        "emitEntryPoint": true,
        "preserveCompilationContext": true
    },

    "runtimeOptions": {
        "configProperties": {
            "System.GC.Server": true
        }
    },

    "publishOptions": {
        "include": [
            "wwwroot",
            "**/*.cshtml",
            "appsettings.json",
            "web.config"
        ]
    },

    "scripts": {
        "prepublish": [ "bower install", "dotnet bundle" ],
        "postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
    }

appsettings with connection string:

{
  "ApplicationInsights": {
    "InstrumentationKey": ""
  },
  "ConnectionStrings": {
    "DefaultConnection": "Server=(local);Database=MyDb;Trusted_Connection=True;MultipleActiveResultSets=true"
  },
  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Debug",
      "System": "Information",
      "Microsoft": "Information"
    }
  }
}

Configuration in Stratup.cs

public void ConfigureServices(IServiceCollection services)
        {
            try
            {
                var migrationAssemblyName = "My.WebSite";
                services.AddDbContext<AuctionContext>(options =>
                    options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"), b => b.MigrationsAssembly(migrationAssemblyName)));
                services.AddDbContext<EntireMoneyProcessingContext>(options =>
                    options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"), b => b.MigrationsAssembly(migrationAssemblyName)));
                services.AddDbContext<OrderContext>(options =>
                    options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"), b => b.MigrationsAssembly(migrationAssemblyName)));
                services.AddDbContext<WorkContext>(options =>
                    options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"), b => b.MigrationsAssembly(migrationAssemblyName)));
                services.AddDbContext<UserContextExt>(options =>
                    options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"), b => b.MigrationsAssembly(migrationAssemblyName)));
                services.AddDbContext<PersonalStoreContext>(options =>
                    options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"), b => b.MigrationsAssembly(migrationAssemblyName)));
                services.AddDbContext<StoreContext>(options =>
                    options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"), b => b.MigrationsAssembly(migrationAssemblyName)));

                services.AddIdentity<User, Role>()
                    .AddUserStore<UserStore<User, Role, UserContextExt, int>>()
                    .AddRoleStore<RoleStore<Role, UserContextExt, int>>()
                    .AddEntityFrameworkStores<UserContextExt, int>()
                    .AddDefaultTokenProviders();

                services.AddMvc();

                // Add application services.
                services.AddTransient<IEmailSender, AuthMessageSender>();
                services.AddTransient<ISmsSender, AuthMessageSender>();
            }
            catch (Exception ex)
            {
                throw;
            }

            // Add framework services.
            services.AddApplicationInsightsTelemetry(Configuration);
        }

Note

I tried to run migrations when web project and context projects are within solution. It worked. Feel free to use the odec.* packages in project.json to reproduce. (they are published on NuGet)

bricelam commented 7 years ago

Hmm... It looks like ConfigureServices isn't getting called, but I'm not sure why just from the code you provided. Any hints in the verbose output? If not, could you share a full repro so we can investigate on our end?

As workaround, you could try adding implementations of IDbContextFactory<TContext> in your startup project, but we should still try and understand the underlying issue.

Defee commented 7 years ago

OK. Will create repo and push today.

Defee commented 7 years ago

@bricelam, here is the repository where you can reproduce Issue: https://github.com/Defee/EF.Packages.Issue

I've found the issue that causes this strange behaviour: If context has only constructor with DbOptions param - all works like a charm(ex: CategoryContext). But if it has any other constructors (like WorkContext) for ex default constructor, it will crash with the exception specified in Issue post. So, it seems dotnet ef calls first constructor it could get. I think that having a separate constructor (or customized one) is normal option for many people, so , it seems like a bug.

bricelam commented 7 years ago

This is a duplicate of #6826

nambir commented 7 years ago

Hi bricelam , do you able to find solution for "# ConfigureServices" isn't getting called

smitpatel commented 7 years ago

@nambir - Remove parameterless ctor from your DbContext that should fix it.