Почему LazyServiceProvider нельзя внедрить в AbpDbContext в тестах?C#

Место общения программистов C#
Ответить
Anonymous
 Почему LazyServiceProvider нельзя внедрить в AbpDbContext в тестах?

Сообщение Anonymous »

У меня есть одноуровневый проект abp.io, v8.3.4.
Я реконструировал тестовую среду, поскольку она, похоже, предоставляется только тогда, когда вы создаете многоуровневое приложение. Я пытаюсь избежать этого (многоуровневой части), поскольку это простой проект, и мне не нужен такой уровень сложности.
У меня проблемы с запуском тестов, использующих мой собственный контекст БД.
Контекст не зарегистрирован, несмотря на то, что я это сделал:
private void ConfigureEfCore(ServiceConfigurationContext context)
{
// This should register the DbContext and the repositories
context.Services.AddAbpDbContext(options =>
{
/* create default repositories only for aggregate roots
* Documentation: https://docs.abp.io/en/abp/latest/Entit ... positories
*/
options.AddDefaultRepositories(includeAllEntities: true);
});

Configure(options =>
{
options.Configure(configurationContext => { configurationContext.UseSqlite(options => { }); });
});
}

Тем не менее, когда я запускаю тест, во время SeedTestData() он выдает:

.... ...

Autofac.Core.Registration.ComponentNotRegisteredException
The requested service 'WFT.CameraControl.Data.CameraControlDbContext' has not been registered. To avoid this exception, either register a component to provide the service, check for service registration using IsRegistered(), or use the ResolveOptional() method to resolve an optional dependency.


Должен добавить, что само приложение работает нормально.
  • Я проверил, что .AddAbpDbContext( ).
  • В тестовой DLL (перечисленной ниже) есть только один AbpModule.
  • Я настраиваю базу данных SQLLite после выполнения регистрация контекста БД в «обычном приложении». И в этом случае, поскольку код на самом деле не использует НАСТОЯЩИЙ модуль приложения, я явно настроил AbpDbContextOptions на UseSqlLite
Любые идеи, где я ошибаюсь?

Вот контекст моей базы данных:

using AppAny.Quartz.EntityFrameworkCore.Migrations;
using AppAny.Quartz.EntityFrameworkCore.Migrations.PostgreSQL;
using Microsoft.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore.Modeling;
using Volo.Abp.AuditLogging.EntityFrameworkCore;
using Volo.Abp.BackgroundJobs.EntityFrameworkCore;
using Volo.Abp.BlobStoring.Database.EntityFrameworkCore;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.FeatureManagement.EntityFrameworkCore;
using Volo.Abp.Identity;
using Volo.Abp.Identity.EntityFrameworkCore;
using Volo.Abp.OpenIddict.EntityFrameworkCore;
using Volo.Abp.PermissionManagement.EntityFrameworkCore;
using Volo.Abp.SettingManagement.EntityFrameworkCore;
using Volo.Abp.TenantManagement;
using Volo.Abp.TenantManagement.EntityFrameworkCore;
using WFT.CameraControl.Entities;

namespace WFT.CameraControl.Data;

[ReplaceDbContext(typeof(IIdentityDbContext))]
[ReplaceDbContext(typeof(ITenantManagementDbContext))]
[ConnectionStringName("Default")]
public class CameraControlDbContext : AbpDbContext, ITenantManagementDbContext,
IIdentityDbContext
{
public const string DbTablePrefix = "App";
public const string DbSchema = null;

#region Entities from the modules

/* Notice: We only implemented IIdentityProDbContext and ISaasDbContext
* and replaced them for this DbContext. This allows you to perform JOIN
* queries for the entities of these modules over the repositories easily. You
* typically don't need that for other modules. But, if you need, you can
* implement the DbContext interface of the needed module and use ReplaceDbContext
* attribute just like IIdentityProDbContext and ISaasDbContext.
*
* More info: Replacing a DbContext of a module ensures that the related module
* uses this DbContext on runtime. Otherwise, it will use its own DbContext class.
*/

// Identity
public DbSet Users { get; set; }
public DbSet Roles { get; set; }
public DbSet ClaimTypes { get; set; }
public DbSet OrganizationUnits { get; set; }
public DbSet SecurityLogs { get; set; }
public DbSet LinkUsers { get; set; }
public DbSet UserDelegations { get; set; }
public DbSet Sessions { get; set; }

// Tenant Management
public DbSet Tenants { get; set; }
public DbSet TenantConnectionStrings { get; set; }

#endregion

// The sites, cameras and doors that are being monitored for this tenant
public DbSet Sites { get; set; }
public DbSet Cameras { get; set; }
public DbSet OpenableResources { get; set; }
public DbSet CameraSessions { get; set; }

public CameraControlDbContext(DbContextOptions options)
: base(options)
{
Console.Out.WriteLine("CameraControlDbContext created");
}

protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);

/* Include modules to your migration db context */

builder.ConfigurePermissionManagement();
builder.ConfigureSettingManagement();
builder.ConfigureBackgroundJobs();
builder.ConfigureAuditLogging();
builder.ConfigureFeatureManagement();
builder.ConfigureIdentity();
builder.ConfigureOpenIddict();
builder.ConfigureTenantManagement();
builder.ConfigureBlobStoring();

// ConfigureQuartzTables(builder);

/* Configure your own entities here */
builder.Entity(b =>
{
b.ToTable("WFT_Sites", DbSchema);
b.ConfigureByConvention();

b.HasMany(s => s.Cameras).WithOne(c => c.Site);
b.HasMany(s => s.OpenableResources).WithOne(o => o.Site);
b.ApplyObjectExtensionMappings();
});

builder.Entity(b =>
{
b.ToTable("WFT_Cameras", DbSchema);
b.ConfigureByConvention();

b.HasMany(ca => ca.Actions)
.WithOne(a => a.Camera)
.HasForeignKey(ca => ca.Id);

b.HasIndex(c => c.CameraIdentifier).IsUnique();
b.ApplyObjectExtensionMappings();
});

builder.Entity(b =>
{
b.ToTable("WFT_CameraActions", DbSchema);
b.ConfigureByConvention();

b.HasOne().WithMany(c => c.Actions);
b.ApplyObjectExtensionMappings();
});

builder.Entity(b =>
{
b.ToTable("WFT_OpenableResources", DbSchema);
b.ConfigureByConvention();

b.HasIndex(r => r.ResourceIdentifier).IsUnique();
b.ApplyObjectExtensionMappings();
});

builder.Entity(b =>
{
b.ToTable("WFT_CameraSessions", DbSchema);
b.ConfigureByConvention();

// Map this so that we're a json column for this structure
b.OwnsOne(cs => cs.LprEvent, d =>
{
d.ToJson();
d.OwnsOne(evt => evt.Data);
});
b.ApplyObjectExtensionMappings();
});
}

private void ConfigureQuartzTables(ModelBuilder builder)
{
builder.AddQuartz(b => { b.UsePostgreSql(schema: DbSchema); });
}
}
```

---

And here is the entire test-module setup, for reference:

```
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Serilog;
using Volo.Abp;
using Volo.Abp.Account;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.AuditLogging.EntityFrameworkCore;
using Volo.Abp.Authorization;
using Volo.Abp.Autofac;
using Volo.Abp.AutoMapper;
using Volo.Abp.BackgroundJobs;
using Volo.Abp.BackgroundJobs.EntityFrameworkCore;
using Volo.Abp.BlobStoring.Database.EntityFrameworkCore;
using Volo.Abp.Caching;
using Volo.Abp.Data;
using Volo.Abp.Emailing;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore.Sqlite;
using Volo.Abp.FeatureManagement;
using Volo.Abp.FeatureManagement.EntityFrameworkCore;
using Volo.Abp.Identity;
using Volo.Abp.Identity.EntityFrameworkCore;
using Volo.Abp.Modularity;
using Volo.Abp.MultiTenancy;
using Volo.Abp.OpenIddict.EntityFrameworkCore;
using Volo.Abp.PermissionManagement;
using Volo.Abp.PermissionManagement.EntityFrameworkCore;
using Volo.Abp.SettingManagement;
using Volo.Abp.SettingManagement.EntityFrameworkCore;
using Volo.Abp.TenantManagement;
using Volo.Abp.TenantManagement.EntityFrameworkCore;
using Volo.Abp.Threading;
using Volo.Abp.Uow;
using WFT.CameraControl;
using WFT.CameraControl.Data;

namespace WFT.CameraControlTests.Base;

[DependsOn(
typeof(AbpAutofacModule),
typeof(AbpTestBaseModule),
typeof(AbpAuthorizationModule),
typeof(AbpBackgroundJobsAbstractionsModule),

// ABP Framework packages
typeof(AbpAutoMapperModule),
typeof(AbpCachingModule),

// Application
typeof(AbpAccountApplicationModule),
typeof(AbpAccountApplicationContractsModule),
typeof(AbpPermissionManagementApplicationModule),
typeof(AbpIdentityApplicationModule),
typeof(AbpAccountApplicationModule),
typeof(AbpTenantManagementApplicationModule),
typeof(AbpSettingManagementApplicationModule),

// EFCore
typeof(AbpPermissionManagementEntityFrameworkCoreModule),
typeof(AbpSettingManagementEntityFrameworkCoreModule),
typeof(AbpBackgroundJobsEntityFrameworkCoreModule),
typeof(AbpAuditLoggingEntityFrameworkCoreModule),
typeof(AbpFeatureManagementEntityFrameworkCoreModule),
typeof(AbpIdentityEntityFrameworkCoreModule),
typeof(AbpOpenIddictEntityFrameworkCoreModule),
typeof(AbpTenantManagementEntityFrameworkCoreModule),
typeof(BlobStoringDatabaseEntityFrameworkCoreModule),
typeof(AbpEntityFrameworkCoreSqliteModule)

// For Background jobs, managed by Quartz
// Fails if you run more than one test at a time, as it tries to instantiate many singleton Quartz schedulers
// So for now, we'll just use the in-memory background job manager
// typeof(AbpBackgroundJobsQuartzModule),
)]
public class CameraControlTestBaseModule : AbpModule
{
/*
* We have to replicate much of what the main App Module does
* Because we can't depend on it in the test project (don't want all of it's HTTP imports)
*/
public override void PreConfigureServices(ServiceConfigurationContext context)
{
Log.Logger = new LoggerConfiguration()
.WriteTo.Async(c => c.Console())
.CreateBootstrapLogger();

// https://www.npgsql.org/efcore/release-n ... ping-logic
AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);

PreConfigure(builder =>
{
builder.AddValidation(options =>
{
options.AddAudiences("CameraControl");
options.UseLocalServer();
options.UseAspNetCore();
});
});
// PreConfigure(options => { options.IsBlazorWebApp = true; });

CameraControlGlobalFeatureConfigurator.Configure();
CameraControlModuleExtensionConfigurator.Configure();
}

public override void ConfigureServices(ServiceConfigurationContext context)
{
// Turn off job execution...
Configure(options => { options.IsJobExecutionEnabled = false; });
context.Services.Replace(ServiceDescriptor.Singleton());
context.Services.AddAlwaysAllowAuthorization();

ConfigureMultiTenancy();
ConfigureAutoMapper(context);
ConfigureAutoApiControllers();
ConfigureEfCore(context);

// add in the assembly, which results in registering the services
// this is so that all the services and repositories are registered, so we can use them in the test
// var cameraControlAssembly = Assembly.GetAssembly(typeof(CameraControlAppService));
// if (cameraControlAssembly != null) context.Services.AddAssembly(cameraControlAssembly);

// EF Core
Configure(options =>
{
options.SaveStaticFeaturesToDatabase = false;
options.IsDynamicFeatureStoreEnabled = false;
});
Configure(options =>
{
options.SaveStaticPermissionsToDatabase = false;
options.IsDynamicPermissionStoreEnabled = false;
});
context.Services.AddAlwaysDisableUnitOfWorkTransaction();

ConfigureInMemorySqlite(context.Services);
}

private void ConfigureEfCore(ServiceConfigurationContext context)
{
// This should register the DbContext and the repositories
context.Services.AddAbpDbContext(options =>
{
/* create default repositories only for aggregate roots
* Documentation: https://docs.abp.io/en/abp/latest/Entit ... positories
*/
options.AddDefaultRepositories(includeAllEntities: true);
});

Configure(options =>
{
options.Configure(configurationContext => { configurationContext.UseSqlite(options => { }); });
});
}

private void ConfigureAutoApiControllers()
{
Configure(options =>
{
options.ConventionalControllers.Create(typeof(CameraControlModule).Assembly);
});
}

private void ConfigureMultiTenancy()
{
Configure(options => { options.IsEnabled = CameraControlModule.IsMultiTenant; });
}

private void ConfigureAutoMapper(ServiceConfigurationContext context)
{
context.Services.AddAutoMapperObjectMapper();
Configure(options =>
{
/* Uncomment `validate: true` if you want to enable the Configuration Validation feature.
* See AutoMapper's documentation to learn what it is:
* https://docs.automapper.org/en/stable/C ... ation.html
*/
options.AddMaps( /* validate: true */);
});
}

public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
SeedTestData(context);
}

private static void SeedTestData(ApplicationInitializationContext context)
{
AsyncHelper.RunSync(async () =>
{
using (var scope = context.ServiceProvider.CreateScope())
{
await scope.ServiceProvider
.GetRequiredService()
.SeedAsync();
}
});
}

// In memory SQLLite DB Stuff
public override void OnApplicationShutdown(ApplicationShutdownContext context)
{
_sqliteConnection?.Dispose();
}

private SqliteConnection? _sqliteConnection;

private void ConfigureInMemorySqlite(IServiceCollection services)
{
_sqliteConnection = CreateDatabaseAndGetConnection();

services.Configure(options =>
{
options.Configure(context => { context.DbContextOptions.UseSqlite(_sqliteConnection); });
});
}
private static SqliteConnection CreateDatabaseAndGetConnection()
{
var connection = new SqliteConnection("Data Source=:memory:");
connection.Open();

var options = new DbContextOptionsBuilder()
.UseSqlite(connection)
.Options;

using (var context = new CameraControlDbContext(options))
{
context.GetService().CreateTables();
}

return connection;
}

}
```



Подробнее здесь: https://stackoverflow.com/questions/792 ... t-in-tests
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»