繁体   English   中英

在 .NET 核心控制台应用程序中为 EF Core DbContext 服务错误建立依赖注入

[英]Established dependency injection in .NET Core Console Application for EF Core DbContext Service Error

我创建了一个 .net 核心控制台应用程序,并添加了以下依赖注入 package:

Microsoft.Extensions.DependencyInjection

要注入 EF Core DbContext 服务,下面是项目的代码片段:

static void Main(string[] args)
        {
            // Create service collection and configure our services
            var services = ConfigureServices();

            // Generate a provider
            var serviceProvider = services.BuildServiceProvider();

            // Kick off our actual code
            serviceProvider.GetService<Startup>().Run();
        }

        public static IConfiguration LoadConfiguration()
        {
            var builder = new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
                .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", optional: true)
                .AddEnvironmentVariables();

            return builder.Build();
        }


private static IServiceCollection ConfigureServices()
        {
            IServiceCollection services = new ServiceCollection();

            // Set up the objects we need to get to configuration settings
            var configuration = LoadConfiguration();


            // IMPORTANT! Register our cvonfig file, db connection string, and application entry point(startup)
            services
                .AddSingleton(configuration)
                .AddConnection(configuration)
                .AddStartup();
            
            return services;
        }

服务池 CLass:

  public static class ServicesPool
    {
        public static IServiceCollection AddStartup(this IServiceCollection services)
        {
            services.AddTransient<Startup>();

            return services;
        }

        public static IServiceCollection AddConfiggguration(this IServiceCollection services, IConfiguration configuration)
        {
            services.AddSingleton(configuration);

            return services;
        }

        public static IServiceCollection AddConnection(this IServiceCollection services, IConfiguration configuration)
        {
            var connection = configuration.GetConnectionString("DEV_CS");
            services.AddDbContext<MigrationDbContext>(options =>
            options.UseSqlServer(connection, b => b.MigrationsAssembly("migration.presentence")));

            return services;
        }

    }

从 EntityFramwork Core 实现 DbContext 的 MigrationDbContext 服务:

public class MigrationDbContext : DbContext
    {
        public MigrationDbContext(DbContextOptions dbContextOptions) : base(dbContextOptions)
        {
        }

        public DbSet<RootItemMigrationEntity> RootItems { get; set; }

    }

应用程序运行没有任何问题,但是当我尝试使用以下命令创建初始迁移时:

添加迁移“初始”

发生错误并显示以下消息:

无法创建“MigrationDbContext”类型的 object。 有关设计时支持的不同模式,请参阅https://go.microsoft.com/fwlink/?linkid=851728

我一直在调查这个问题,我尝试了多种解决方案,但我还没有解决它。 因此,我将分享错误的堆栈跟踪,希望得到您的帮助!

堆栈跟踪:

PM> Add-Migration 'Initial' -verbos 使用项目'migration.presentence'。 使用启动项目“e-commerce.migration”。 构建开始...构建成功。 C:\Program Files\dotnet\dotnet.exe exec --depsfile C:\dev\backlogheros\e-commerce.migration\e-commerce.migration\bin\Debug\netcoredapp5.0\e-commerce.migration。 json --additionalprobingpath C:\Users\yousi.nuget\packages --runtimeconfig C:\dev\backlogheros\e-commerce.migration\e-commerce.migration\bin\Debug\netcoreapp5.0\e-commerce.migration. runtimeconfig.json C:\Users\yousi.nuget\packages\microsoft.entityframeworkcore.tools\5.0.1\tools\netcoreapp2.0\any\ef.dll migrations add Initial --json --verbose --no-color - -prefix-output --assembly C:\dev\backlogheros\e-commerce.migration\e-commerce.migration\bin\Debug\netcoreapp5.0\migration.presentence.dll --startup-assembly Z0D6 1F8370CAD1D412F80B84D143E1257Z:\dev\backlogheros\e-commerce.migration\e-commerce.migration\bin\Debug\netcoreapp5.0\e-commerce.migration.dll --project-dir C:\dev\backlogheros\e-commerce.迁移\migration.presentence
--language C# --working-dir C:\dev\backlogheros\e-commerce.migration --root-namespace migration.presentence 使用程序集“migration.presentence”。 使用启动程序集“e-commerce.migration”。 使用应用程序库“C:\dev\backlogheros\e-commerce.migration\e-commerce.migration\bin\Debug\netcoreapp5.0”。 使用工作目录'C:\dev\backlogheros\e-commerce.migration\e-commerce.migration'。 使用根命名空间“migration.presentence”。 使用项目目录'C:\dev\backlogheros\e-commerce.migration\migration.presentence'。 剩余的 arguments:。 查找 DbContext 类...查找 IDesignTimeDbContextFactory 实现...查找程序集“e-commerce.migration”中的应用程序服务提供程序...查找 Microsoft.Extensions.Hosting 服务提供程序...无 static 方法“CreateHostBuilder(string[])”在 class '程序'上找到。 未找到应用程序服务提供者。 在项目中查找 DbContext 类...找到 DbContext 'MigrationDbContext'。 Microsoft.EntityFrameworkCore.Design.OperationException:无法创建“MigrationDbContext”类型的 object。 有关设计时支持的不同模式,请参阅https://go.microsoft.com/fwlink/?linkid=851728 ---> System.InvalidOperationException: Unable to resolve service for type 'Microsoft.EntityFrameworkCore.DbContextOptions' while trying to激活'migration.presentence.MigrationDbContext'。

at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.ConstructorMatcher.CreateInstance(IServiceProvider provider)   
at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.CreateInstance(IServiceProvider provider, Type instanceType, Object[] parameters)    
at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetServiceOrCreateInstance(IServiceProvider provider, Type type)    
at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.<>c__DisplayClass13_4.<FindContextTypes>b__13()
--- End of inner exception stack trace ---    
at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.<>c__DisplayClass13_4.<FindContextTypes>b__13()
at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(Func`1 factory)    
at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(String contextType)    
at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.AddMigration(String name, String outputDir, String contextType, String namespace)    
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigrationImpl(String name, String outputDir, String contextType, String namespace)    
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigration.<>c__DisplayClass0_0.<.ctor>b__0()
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_0`1.<Execute>b__0()
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)

迁移工具必须实例化您的 DbContext 才能创建迁移。 它有 3 种方法可以做到这一点:

  1. 从服务提供商处解决
  2. 新的()
  3. IDesignTimeDbContextFactory

从服务提供商处解决

如果您希望迁移工具使用应用程序配置并从服务提供商处解析 DbContext,则有多个要求,如https://go.microsoft.com/fwlink/?linkid=851728页所述。

首先,您需要有一个在您的DbContextOptions上采用 DbContextOptions 的构造函数。 那部分没问题,只有在程序集中有多个 DbContext 时才需要指定DbContextOptions<TContext>

Second, you must use a host builder (either ASP.NET, HTTP or Generic) and the tool will look for a public static CreateHostBuilder(string[] args) method in class Program to access it. 这对您的基础架构类有很多副作用,因为IHostBuilder将为您完成大部分ServiceCollectionConfigurationBuilder的工作。

此外,您的 DbContext 需要注册为 singleton,这可能是个问题。

程序.cs

internal class Program
{
    public static void LoadConfiguration(HostBuilderContext host, IConfigurationBuilder builder)
    {
        builder
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
            .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", optional: true)
            .AddEnvironmentVariables();
    }

    private static void ConfigureServices(HostBuilderContext host, IServiceCollection services)
    {
        services
            .AddDbContext<MigrationDbContext>(options =>
            {
                options.UseSqlServer(
                    host.Configuration.GetConnectionString("DEV_CS"), builder =>
                        builder.MigrationsAssembly("migration.presentence"));
            }, ServiceLifetime.Singleton)
            .AddHostedService<Startup>();
    }

    private static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration(LoadConfiguration)
            .ConfigureServices(ConfigureServices);

    private static async Task Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }
}

为了让您的主机构建器运行您的自定义代码,您还需要将Startup class 转换为IHostedService ,例如BackgroundService

启动.cs

internal class Startup : BackgroundService
{
    private readonly MigrationDbContext context;

    public Startup(MigrationDbContext context)
    {
        this.context = context ?? throw new ArgumentNullException(nameof(context));
    }

    protected override Task ExecuteAsync(CancellationToken stoppingToken)
    {
        throw new NotImplementedException();
    }
}

新的()

另一种选择是在 DbContext 上使用默认构造。 但是,在这种情况下,您不能同时拥有默认构造函数和DbContextOptions构造函数。 伤心。

IDesignTimeDbContextFactory

在您的情况下,最简单的解决方案可能是实现IDesignTimeDbContextFactory<TContext> 如果找不到IHostBuilder并且 DbContext 使用DbContextOptions构造函数,则工具将使用此 class。 实现非常简单:

internal class MigrationDbContextFactory : IDesignTimeDbContextFactory<MigrationDbContext>
{
    public MigrationDbContext CreateDbContext(string[] args)
    {
        var optionsBuilder = new DbContextOptionsBuilder<MigrationDbContext>();
        optionsBuilder.UseSqlServer("Server=(localdb)\\mssqllocaldb;Database=Test",
            b => b.MigrationsAssembly("migration.presentence"));
        return new MigrationDbContext(optionsBuilder.Options);
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM