Layerd Web App - проблема с добавлением миграции - PullRequest
0 голосов
/ 05 ноября 2019

У меня многоуровневое веб-приложение, в котором проект Infrastructure содержит только Identities, а Persistence содержит все другие объекты. Для постоянства мне удалось создать миграцию, но для инфраструктуры не удалось. Разница между этими двумя заключается в том, что сохраняемость наследует DbContext и Infrastrutcure ApiAuthorizationDbContext

Код ниже:

public class ApplicationDbContext : ApiAuthorizationDbContext<ApplicationUser>
{
    public ApplicationDbContext(
        DbContextOptions<ApplicationDbContext> options,
        IOptions<OperationalStoreOptions> operationalStoreOptions) : base(options, operationalStoreOptions)
    {

    }
}  public class IMSDbContext : DbContext, IIMSDbContext
    {
        private readonly ICurrentUserService _currentUserService;
        private readonly IDateTime _dateTime;

        public IMSDbContext(DbContextOptions<IMSDbContext> options) : base(options)
        {

        }

        public IMSDbContext(DbContextOptions<IMSDbContext> options, ICurrentUserService currentUserService, IDateTime dateTime) : base(options)
        {
            _currentUserService = currentUserService;
            _dateTime = dateTime;
        }


        public DbSet<ItemType> ItemTypes { get; set; }
        public DbSet<Item> Items { get; set; }
        public DbSet<Employee> Employees { get; set; }
        public DbSet<ItemDetail> ItemDetails { get; set; }
        public DbSet<Location> Locations { get; set; }
        public DbSet<ItemImage> ItemImages { get; set; }

        public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = new CancellationToken())
        {

            foreach (var entry in ChangeTracker.Entries<AuditableEntity>())
            {
                switch (entry.State)
                {
                    case EntityState.Added:
                        entry.Entity.CreatedBy = _currentUserService.UserId;
                        entry.Entity.Created = _dateTime.Now;
                        break;
                    case EntityState.Modified:
                        entry.Entity.ModifiedBy = _currentUserService.UserId;
                        entry.Entity.Modified = _dateTime.Now;
                        break;

                }
            }
            return base.SaveChangesAsync(cancellationToken);
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.ApplyConfigurationsFromAssembly(typeof(IMSDbContext).Assembly);
        }
    }

Когда я запускаю добавочную миграцию -p Инфраструктура -c ApplicationDbContext из проекта Persistence, где установленEFCore.Design Получена следующая ошибка:

Невозможно создать объект типа 'ApplicationDbContext'. Для различных шаблонов, поддерживаемых во время разработки, см. https://go.microsoft.com/fwlink/?linkid=851728

Вот DI для инфраструктуры:

 public static class DependencyInjection
    {
        public static IServiceCollection AddInfrastructure(this IServiceCollection services,
            IConfiguration configuration, IWebHostEnvironment environment)
        {

            services.AddScoped<IUserManager, UserManagerService>();
            services.AddTransient<INotificationService, NotificationService>();
            services.AddTransient<IDateTime, MachineDateTime>();

            services.AddDbContext<ApplicationDbContext>(
                options => options.UseSqlServer(configuration.GetConnectionString("IMSDatabase")));

            services.AddDefaultIdentity<ApplicationUser>()
                .AddEntityFrameworkStores<ApplicationDbContext>();

            services.AddIdentityServer()
                .AddApiAuthorization<ApplicationUser, ApplicationDbContext>();


            services.AddAuthentication()
                .AddIdentityServerJwt();

            return services;
        }
    }

А вот и запуск из проекта WebAPI.

  public class Startup
    {
        private IServiceCollection _services;
        public Startup(IConfiguration configuration, IWebHostEnvironment environment)
        {
            Configuration = configuration;
            Environment = environment;

        }

        public IConfiguration Configuration { get; }
        public IWebHostEnvironment Environment { get; }


        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddInfrastructure(Configuration, Environment);
            services.AddPersistence(Configuration);
            services.AddApplication();
            services.AddControllers();

            _services = services;
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseHttpsRedirection();

            app.UseRouting();

            app.UseAuthentication();
            app.UseIdentityServer();
            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }

        private void RegisteredServicesPage(IApplicationBuilder app)
        {
            app.Map("/services", builder => builder.Run(async context =>
            {
                var sb = new StringBuilder();
                sb.Append("<h1>Registered Services</h1>");
                sb.Append("<table><thead>");
                sb.Append("<tr><th>Type</th><th>Lifetime</th><th>Instance</th></tr>");
                sb.Append("</thead><tbody>");
                foreach (var svc in _services)
                {
                    sb.Append("<tr>");
                    sb.Append($"<td>{svc.ServiceType.FullName}</td>");
                    sb.Append($"<td>{svc.Lifetime}</td>");
                    sb.Append($"<td>{svc.ImplementationType?.FullName}</td>");
                    sb.Append("</tr>");
                }
                sb.Append("</tbody></table>");
                await context.Response.WriteAsync(sb.ToString());
            }));
        }
    }

Может кто-нибудь помочь мне понять, что я сделал не так? С уважением, Даниэль

ОБНОВЛЕНИЕ При запуске команды pmc:

add-migration Identity -c ApplicationDbContext -p Infrastructure -s Persistence -v
Using project 'src\Infrastructure'.
Using startup project 'src\Persistence'.
Build started...
Build succeeded.
C:\Program Files\dotnet\dotnet.exe exec --depsfile C:\Users\BoksanD\source\repos\IMS\Persistence\bin\Debug\netcoreapp3.0\IMS.Persistence.deps.json --additionalprobingpath C:\Users\BoksanD\.nuget\packages --additionalprobingpath C:\Microsoft\Xamarin\NuGet --additionalprobingpath "C:\Program Files\dotnet\sdk\NuGetFallbackFolder" --runtimeconfig C:\Users\BoksanD\source\repos\IMS\Persistence\bin\Debug\netcoreapp3.0\IMS.Persistence.runtimeconfig.json C:\Users\BoksanD\.nuget\packages\microsoft.entityframeworkcore.tools\3.0.0\tools\netcoreapp2.0\any\ef.dll migrations add Identity --json --context ApplicationDbContext --verbose --no-color --prefix-output --assembly C:\Users\BoksanD\source\repos\IMS\Persistence\bin\Debug\netcoreapp3.0\IMS.Infrastructure.dll --startup-assembly C:\Users\BoksanD\source\repos\IMS\Persistence\bin\Debug\netcoreapp3.0\IMS.Persistence.dll --project-dir C:\Users\BoksanD\source\repos\IMS\Infrastructure\ --language C# --working-dir C:\Users\BoksanD\source\repos\IMS --root-namespace IMS.Infrastructure
Using assembly 'IMS.Infrastructure'.
Using startup assembly 'IMS.Persistence'.
Using application base 'C:\Users\BoksanD\source\repos\IMS\Persistence\bin\Debug\netcoreapp3.0'.
Using working directory 'C:\Users\BoksanD\source\repos\IMS\Persistence'.
Using root namespace 'IMS.Infrastructure'.
Using project directory 'C:\Users\BoksanD\source\repos\IMS\Infrastructure\'.
Finding DbContext classes...
Finding IDesignTimeDbContextFactory implementations...
Found IDesignTimeDbContextFactory implementation 'IMSDbContextFactory'.
Found DbContext 'IMSDbContext'.
Finding application service provider...
Finding Microsoft.Extensions.Hosting service provider...
No static method 'CreateHostBuilder(string[])' was found on class 'Program'.
No application service provider was found.
Finding DbContext classes in the project...
Found DbContext 'ApplicationDbContext'.
Microsoft.EntityFrameworkCore.Design.OperationException: Unable to create an object of type 'ApplicationDbContext'. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728
 ---> System.MissingMethodException: No parameterless constructor defined for type 'IMS.Infrastructure.Identity.ApplicationDbContext'.
   at System.RuntimeType.CreateInstanceDefaultCtorSlow(Boolean publicOnly, Boolean wrapExceptions, Boolean fillCache)
   at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, Boolean wrapExceptions)
   at System.Activator.CreateInstance(Type type, Boolean nonPublic, Boolean wrapExceptions)
   at System.Activator.CreateInstance(Type type)
   at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.<>c__DisplayClass13_3.<FindContextTypes>b__13()
   --- End of inner exception stack trace ---
   at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.<>c__DisplayClass13_3.<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)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigrationImpl(String name, String outputDir, String contextType)
   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)
Unable to create an object of type 'ApplicationDbContext'. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728

А вот Program.cs

namespace IMS.WebAPI
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var host = CreateHostBuilder(args).Build();

            using (var scope = host.Services.CreateScope())
            {
                var services = scope.ServiceProvider;

                try
                {
                    var northwindContext = services.GetRequiredService<IMSDbContext>();
                    northwindContext.Database.Migrate();

                    var identityContext = services.GetRequiredService<ApplicationDbContext>();
                    identityContext.Database.Migrate();

                }
                catch (Exception ex)
                {
                    var logger = scope.ServiceProvider.GetRequiredService<ILogger<Program>>();
                    logger.LogError(ex, "An error occurred while migrating or initializing the database.");
                }
            }

            host.Run();
        }

        public static IWebHostBuilder CreateHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .ConfigureAppConfiguration((hostingContext, config) =>
                {
                    var env = hostingContext.HostingEnvironment;

                    config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                        .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);

                    if (env.IsDevelopment())
                    {
                        var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName));
                        if (appAssembly != null)
                        {
                            config.AddUserSecrets(appAssembly, optional: true);
                        }
                    }

                    config.AddEnvironmentVariables();

                    if (args != null)
                    {
                        config.AddCommandLine(args);
                    }
                })
                .ConfigureLogging((hostingContext, logging) =>
                {
                    logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
                    logging.AddConsole();
                    logging.AddDebug();
                })
                .UseStartup<Startup>();
    }
}
...