首先是 EF Core DB,以及如何避免在模型生成时覆盖构造函数



我将不再在 Azure DB 中使用 SQL 身份验证,而是按照本文所述使用 Active Directory 托管身份验证。

基本上,我正在做两件主要的事情来让它工作。

1-在DBContext构造函数中注入令牌:

public MyDBContext(DbContextOptions<MyDBContext> options)
: base(options)
{
var conn = (SqlConnection)Database.GetDbConnection();
conn.AccessToken = (new Microsoft.Azure.Services.AppAuthentication.AzureServiceTokenProvider()).GetAccessTokenAsync("https://database.windows.net/").Result;
}

2-在我的Web应用程序启动文件中,我正在注入DBContext

string SqlConnection = localConfig["SqlConnectionString"];
services.AddDbContext<MyDBContext>(options => options.UseSqlServer(SqlConnection, sqlServerOptions => { sqlServerOptions.CommandTimeout(1000); }));

我现在的问题是,每次我需要使用Scaffold-DbContext命令刷新模型时,我的MyDbContext都会被覆盖,并且我丢失了对构造函数所做的更改。

有哪些解决方案可以避免此问题?或者,有没有更好的方法来有效地将代币注入其他地方?

编辑:请注意,我使用的是 EF 2.x

我使用拦截器来注入访问令牌:

public class ManagedIdentityConnectionInterceptor : DbConnectionInterceptor
{
private readonly bool _useManagedIdentity;
private readonly AzureServiceTokenProvider _tokenProvider;
public ManagedIdentityConnectionInterceptor(bool useManagedIdentity)
{
_useManagedIdentity = useManagedIdentity;
_tokenProvider = new AzureServiceTokenProvider();
}
public override async Task<InterceptionResult> ConnectionOpeningAsync(
DbConnection connection,
ConnectionEventData eventData,
InterceptionResult result,
CancellationToken cancellationToken = default)
{
if (_useManagedIdentity)
{
// In Azure, get an access token for the connection
var sqlConnection = (SqlConnection)connection;
var accessToken = await GetAccessTokenAsync(cancellationToken);
sqlConnection.AccessToken = accessToken;
}
return result;
}
private async Task<string> GetAccessTokenAsync(CancellationToken cancellationToken)
{
// Get access token for Azure SQL DB
var resource = "https://database.windows.net/";
return await _tokenProvider.GetAccessTokenAsync(resource, cancellationToken: cancellationToken);
}
}

可以像这样添加:

// Detect environment somehow (locally you might not want to use tokens)
var useManagedIdentity = true;
var managedIdentityInterceptor = new ManagedIdentityConnectionInterceptor(useManagedIdentity);
services.AddDbContext<Context>(options => options.UseSqlServer(connectionString).AddInterceptors(managedIdentityInterceptor));

这样,构造函数中就不需要更改。 侦听器将在打开与 SQL DB 的连接之前获取令牌。 此外,我们避免在构造函数中进行异步同步。 请注意,这需要 EF Core 3.x。

您可以将UseSqlServer重载与DbConnection参数一起使用,并传递配置SqlConnection对象:

var sqlConnectionString = localConfig["SqlConnectionString"];
services.AddDbContext<MyDBContext>(
options => options.UseSqlServer(new SqlConnection(sqlConnectionString)
{
AccessToken = (new Microsoft.Azure.Services.AppAuthentication.AzureServiceTokenProvider()).GetAccessTokenAsync("https://database.windows.net/").Result
},
sqlServerOptions => { sqlServerOptions.CommandTimeout(1000); }));

最新更新