如何在 ASP.NET Core 中使用 Hangfire 与 Azure 数据库和 Active Directory 密码身份验证

How to use Hangfire in ASP.NET Core with Azure database and Active Directory Password authentication

我们正在尝试在 ASP.NET Core WebApi 应用程序 (.NET 5) 中首次使用 Hangfire (v1.7.19)。以前他们都是守旧派 ASP.NET,并且工作没有问题。

使用的 Hangfire 包(根据 Hangfire documentation)是 Hangfire.CoreHangfire.SqlServerHangfire.AspNetCore。我们也尝试只使用组合的 Hangfire 包,但结果相同。

直接从该文档页面上的代码中提取,在 ConfigureServices 中我们添加

    services.AddHangfire(configuration => configuration
        .SetDataCompatibilityLevel(CompatibilityLevel.Version_170)
        .UseSimpleAssemblyNameTypeSerializer()
        .UseRecommendedSerializerSettings()
        .UseSqlServerStorage(connectionString), new SqlServerStorageOptions
        {
            CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),
            SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),
            QueuePollInterval = TimeSpan.Zero,
            UseRecommendedIsolationLevel = true,
            DisableGlobalLocks = true
        }));

这在运行时给出

System.ArgumentException
  HResult=0x80070057
  Message=Keyword not supported: 'authentication'.
  Source=System.Data.SqlClient
  StackTrace:
   at System.Data.Common.DbConnectionOptions.ParseInternal(Dictionary`2 parsetable, String connectionString, Boolean buildChain, Dictionary`2 synonyms)
   at System.Data.Common.DbConnectionOptions..ctor(String connectionString, Dictionary`2 synonyms)
   at System.Data.SqlClient.SqlConnectionString..ctor(String connectionString)
   at System.Data.SqlClient.SqlConnectionFactory.CreateConnectionOptions(String connectionString, DbConnectionOptions previous)
   at System.Data.ProviderBase.DbConnectionFactory.GetConnectionPoolGroup(DbConnectionPoolKey key, DbConnectionPoolGroupOptions poolOptions, DbConnectionOptions& userConnectionOptions)
   at System.Data.SqlClient.SqlConnection.ConnectionString_Set(DbConnectionPoolKey key)
   at System.Data.SqlClient.SqlConnection.set_ConnectionString(String value)
   at System.Data.SqlClient.SqlConnection..ctor(String connectionString)
   at Hangfire.SqlServer.SqlServerStorage.<.ctor>b__6_0()
   at Hangfire.SqlServer.SqlServerStorage.CreateAndOpenConnection()
   at Hangfire.SqlServer.SqlServerStorage.UseConnection[T](DbConnection dedicatedConnection, Func`2 func)
   at Hangfire.SqlServer.SqlServerStorage.UseConnection(DbConnection dedicatedConnection, Action`1 action)
   at Hangfire.SqlServer.SqlServerStorage.Initialize()
   at Hangfire.SqlServer.SqlServerStorage..ctor(String nameOrConnectionString, SqlServerStorageOptions options)
   at Hangfire.SqlServer.SqlServerStorage..ctor(String nameOrConnectionString)
   at Hangfire.SqlServerStorageExtensions.UseSqlServerStorage(IGlobalConfiguration configuration, String nameOrConnectionString)

connectionString的值为

Initial Catalog=XXX;Data Source=YYY;Authentication=Active Directory Password;UID=ZZZ;PWD=PPP"

这适用于本地 SqlServer 和 LocalDb,但不适用于 AzureDB。连接字符串正是我们也用于 EntityFrameworkCore 5 的连接字符串(实际上,该值是从 context.Database.GetConnectionString() 分配的)。

我读过 AzureDB 和 .NET Core 存在问题的地方,但这些问题很久以前就已经解决了。查看 Hangfire.SqlServer 包依赖项,我看到它在哪里使用 System.Data.SqlClient,而当前 AzureDB 的文档都使用 Microsoft.Data.SqlClient,这让我认为支持 Active Directory 密码身份验证的增强功能不是在 System.Data.SqlClient 中制作的,而是在较新的 Microsoft.Data.SqlClient 包中制作的。如果是这样的话,我可以请求 Hangfire 替换它的 SqlClient 包,但我想在这样做之前得到确认。

如果确实如此,有什么想法吗?在此期间我们可以做些什么来解决这个问题吗?

提前致谢。

Hangfire IO GitHub Issue 1827

Pointers from Sergey Odinokov

早在 1.7.8 就支持使用 UseSqlServerStorage 的重载,它接受 Func<DbConnection> 而不是连接字符串,您可以在其中使用连接工厂来提供更新的 Microsoft.Data.SqlClient.SqlConnection 支持 Authentication 关键字。

Here is the related source code

你可以这样使用

 services.AddHangfire(config => config
       // other options you listed above removed for brevity
.UseSqlServerStorage(
          () => new Microsoft.Data.SqlClient.SqlConnection(<connection_string>)
          , new SqlServerStorageOptions() {...}
     )
);