Reputation: 3396
On my current project (.NET 5, ASP.NET Core), we're using FluentMigrator for running EF Core migrations which works flawlessly. We're in the process of setting up our infrastructure in Azure to communicate via Managed Identities and have set op a system assigned managed identity from our (web) app service to our SQL server.
We followed this guide to the point: https://learn.microsoft.com/en-us/azure/app-service/app-service-web-tutorial-connect-msi?tabs=windowsclient%2Cdotnetcore
However, we get the following null pointer reference from 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, DbConnectionInternal& connection)
at Microsoft.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal& connection)
at Microsoft.Data.ProviderBase.DbConnectionFactory.TryGetConnection(DbConnection owningConnection, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal oldConnection, DbConnectionInternal& 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()
I'd imagine that it's because FluentMigrator cannot connect to the database using the connection string:
"Server=tcp:<server-name>.database.windows.net;Authentication=Active Directory Device Code Flow; Database=<database-name>;"
But I might be wrong :-)
In StartUp.cs
we register FluentMigrator like this:
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();
}
Does anyone know if it's possible at all to get FluentMigrator to work with AD/Managed Identities in Azure?
Any help/hint is greatly appreciated.
Thanks in advance.
EDIT: our app service runs fine if we comment out the FluentMigrator registration.
Upvotes: 0
Views: 1203
Reputation: 3396
Nothing wrong with FluentMigrator at all. It was just me having a tunnel-vision and followed Microsofts guide where they have put the SqlAuthenticationProvider.SetProvider(...)
inside of services.AddDbContext<T>(...)
:-) Moving it outside of the AddDbContext<T>(..)
like this made it work:
SqlAuthenticationProvider.SetProvider(
SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow,
new ManagedIdentitySqlAuthProvider());
services.AddDbContext<BasketApiDbContext>(options =>
{
options.UseSqlServer(databaseConnectionString);
});
Upvotes: 0