#c# #azure #entity-framework-core #fluent-migrator
Вопрос:
В моем текущем проекте (.NET 5, ASP.NET Core), мы используем FluentMigrator для запуска миграции ядра EF, которая работает безупречно. Мы находимся в процессе настройки нашей инфраструктуры в Azure для взаимодействия с помощью управляемых удостоверений и установили систему, назначающую управляемые удостоверения из нашей (веб -) службы приложений нашему SQL server.
Мы проследили за этим руководством до конца: https://docs.microsoft.com/en-us/azure/app-service/app-service-web-tutorial-connect-msi?tabs=windowsclient,dotnetcore
Тем не менее, мы получаем следующую ссылку на нулевой указатель от FluentMigrator:
FluentMigrator.Runner.Processors.SqlServer.SqlServer2016Processor[0]
There was an exception checking if table VersionInfo in (null) exists
System.AggregateException: One or more errors occurred. (Object reference not set to an instance of an object.)
---> System.NullReferenceException: Object reference not set to an instance of an object.
at Microsoft.Data.SqlClient.ActiveDirectoryAuthenticationProvider.<AcquireTokenInteractiveDeviceFlowAsync>b__18_0(DeviceCodeResult deviceCodeResult)
at Microsoft.Identity.Client.Internal.Requests.DeviceCodeRequest.ExecuteAsync(CancellationToken cancellationToken)
at Microsoft.Identity.Client.Internal.Requests.RequestBase.RunAsync(CancellationToken cancellationToken)
at Microsoft.Identity.Client.ApiConfig.Executors.PublicClientExecutor.ExecuteAsync(AcquireToken CommonParameters commonParameters, AcquireTokenWithDeviceCodeParameters deviceCodeParameters, CancellationToken cancellationToken)
at Microsoft.Data.SqlClient.ActiveDirectoryAuthenticationProvider.AcquireTokenInteractiveDeviceFlowAsync(IPublicClientApplication app, String[] scopes, Guid connectionId, String userId, SqlAuthenticationMethod authenticationMethod, CancellationTokenSource cts)
at Microsoft.Data.SqlClient.ActiveDirectoryAuthenticationProvider.AcquireTokenAsync(SqlAuthenticationParameters parameters)
--- End of inner exception stack trace ---
at Microsoft.Data.ProviderBase.DbConnectionPool.CheckPoolBlockingPeriod(Exception e)
at Microsoft.Data.ProviderBase.DbConnectionPool.CreateObject(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection)
at Microsoft.Data.ProviderBase.DbConnectionPool.UserCreateRequest(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection)
at Microsoft.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, UInt32 waitForMultipleObjectsTimeout, Boolean allowCreate, Boolean onlyOneCheckConnection, DbConnectionOptions userOptions, DbConnectionInternalamp; connection)
at Microsoft.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternalamp; connection)
at Microsoft.Data.ProviderBase.DbConnectionFactory.TryGetConnection(DbConnection owningConnection, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal oldConnection, DbConnectionInternalamp; connection)
at Microsoft.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)
at Microsoft.Data.ProviderBase.DbConnectionClosed.TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)
at Microsoft.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource`1 retry, SqlConnectionOverrides overrides)
at Microsoft.Data.SqlClient.SqlConnection.Open(SqlConnectionOverrides overrides)
at Microsoft.Data.SqlClient.SqlConnection.Open()
at FluentMigrator.Runner.Processors.GenericProcessorBase.<>c__DisplayClass6_1.<.ctor>b__1()
Я бы предположил, что это потому, что FluentMigrator не может подключиться к базе данных с помощью строки подключения:
"Server=tcp:<server-name>.database.windows.net;Authentication=Active Directory Device Code Flow; Database=<database-name>;"
Но я могу ошибаться
В StartUp.cs
мы регистрируем FluentMigrator вот так:
public void ConfigureServices(IServiceCollection services)
{
services.AddFluentMigratorCore()
.ConfigureRunner(rb => rb
.AddSqlServer()
.WithGlobalConnectionString(databaseConnectionString)
.ScanIn(typeof(Startup).Assembly).For.Migrations());
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
using IServiceScope scope = app.ApplicationServices.CreateScope();
IMigrationRunner runner = scope.ServiceProvider.GetRequiredService<IMigrationRunner>();
runner.MigrateUp();
}
Кто-нибудь знает, возможно ли вообще заставить FluentMigrator работать с объявлениями/управляемыми идентификаторами в Azure?
Любая помощь/подсказка будет высоко оценена.
Заранее спасибо.
РЕДАКТИРОВАТЬ: наш сервис приложений работает нормально, если мы закомментируем регистрацию FluentMigrator.
Комментарии:
1. Мне на самом деле любопытно увидеть вашу реализацию в том, чтобы заставить FluentMigrator запускать миграции EF. Как вы настроили FluentMigrator, чтобы он мог распознавать классы миграции EF?
Ответ №1:
В FluentMigrator вообще нет ничего плохого. Просто у меня было туннельное зрение, и я следовал руководству Microsofts, где они поместили SqlAuthenticationProvider.SetProvider(...)
внутреннюю часть services.AddDbContext<T>(...)
: -) Перемещение его за пределы AddDbContext<T>(..)
, как это, заставило его работать:
SqlAuthenticationProvider.SetProvider(
SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow,
new ManagedIdentitySqlAuthProvider());
services.AddDbContext<BasketApiDbContext>(options =>
{
options.UseSqlServer(databaseConnectionString);
});