Я создаю приложение, которое включает IdentityServer4, используя. NET Core 3.1 и Entity Framework Core. Предполагается, что он может работать с несколькими типами баз данных.
Следуя различным примерам, мне удалось настроить его как на SQL Server, так и на MySQL, используя две отдельные сборки миграции в дополнение к самому проекту IdentityServer. который содержит DbContexts.
В Startup.cs у меня есть следующее:
var migrationsAssembly = $"IdentityServer.Migrations.{serverType}";
services.AddDbContext<Data.IdentityServerContext>(options =>
{
switch (serverType)
{
case ServerType.SqlServer:
options.UseSqlServer(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly));
break;
case ServerType.MySql:
options.UseMySql(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly));
break;
}
});
Где ServerType - это перечисление конфигурации "SqlServer" или "MySql"
Если я использую командную строку do tnet, миграция будет работать правильно
dotnet ef database update -c IdentityServerContext
I wi sh, чтобы иметь возможность использовать конфигурацию или командную строку, чтобы IdentityServer сам применил миграции .
например, в Main ()
var host = CreateHostBuilder(args).Build();
using (var scope = host.Services.CreateScope())
{
var provider = scope.ServiceProvider;
try
{
var configuration = provider.GetRequiredService<IConfiguration>();
if (configuration.GetValue<bool>("migrateDatabases"))
{
var identityContext = provider.GetRequiredService<IdentityServerContext>();
identityContext.Database.Migrate();
}
}
catch
{
}
}
host.Run();
Однако, если я сделаю это, я получу исключение:
System.IO.FileNotFoundException: Could not load file or assembly 'IdentityServer.Migrations.MySql, Culture=neutral, PublicKeyToken=null'. The system cannot find the file specified.
File name: 'IdentityServer.Migrations.MySql, Culture=neutral, PublicKeyToken=null'
at System.Reflection.RuntimeAssembly.nLoad(AssemblyName fileName, String codeBase, RuntimeAssembly assemblyContext, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, AssemblyLoadContext assemblyLoadContext)
at System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(AssemblyName assemblyRef, StackCrawlMark& stackMark, AssemblyLoadContext assemblyLoadContext)
at System.Reflection.Assembly.Load(AssemblyName assemblyRef, StackCrawlMark& stackMark, AssemblyLoadContext assemblyLoadContext)
at System.Reflection.Assembly.Load(AssemblyName assemblyRef)
at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationsAssembly..ctor(ICurrentDbContext currentContext, IDbContextOptions options, IMigrationsIdGenerator idGenerator, IDiagnosticsLogger`1 logger)
at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)
at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass1_0.<RealizeService>b__0(ServiceProviderEngineScope scope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetService[T](IServiceProvider provider)
at Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.GetRelationalService[TService](IInfrastructure`1 databaseFacade)
at Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.Migrate(DatabaseFacade databaseFacade)
at IdentityServer.Program.Main(String[] args)
Сборка миграции находится в том же каталоге, что и DLL проекта и EXE.
Что я не могу понять, так это , почему не может загрузить сборку миграции.
В качестве эксперимента я установил обратный вызов AssemblyLoadContext.Default.Resolving
и использовал * 1 028 * чтобы загрузить сборку вручную. Это работает и применяет перенос правильно, но это очень грязный обходной путь.
Может ли кто-нибудь пролить свет на причину сбоя загрузки сборки при вызове из context.Database.Migrate()
, но не при использовании инструментов ef или при загрузке вручную в Resolving
обратном вызове?
Edit
Я думаю, что нашел обходной путь, который соответствует тому, что мы делаем в другом проекте в том же решении.
Мы динамически загружаем модули в Dot Net Core DI framework во время выполнения в этом проекте, и миграции в модулях работают правильно.
Я добавил Scutor
библиотека проекта для сканирования загруженных вручную сборок миграции в коллекцию служб DI. Даже если он не регистрирует какие-либо классы, этого, по-видимому, достаточно для загрузки сборки в AssemblyLoadContext
, чтобы код миграции мог ее загрузить.
Однако это не объясняет, почему он не может загрузить сборки миграции автоматически.