AddDbContext中创建的SqlConnection对象应该在哪里处置比较好?(.Net Core 2.2)

4

我试图让Azure托管标识认证与我的应用程序配合使用,我将在Azure App Service上部署该应用程序以连接到Azure SQL服务器。

经过查看一些示例和样本代码后,我尝试以下实现:

services.AddDbContext<MainContext>(optionsBuilder =>
{
    SqlConnection connection = new SqlConnection();
    connection.ConnectionString = Configuration.GetConnectionString("DefaultConnection");
    connection.AccessToken = (new AzureServiceTokenProvider()).GetAccessTokenAsync("https://database.windows.net/").Result;

    optionsBuilder.UseSqlServer(connection);
});

这个SqlConnection的正确处理位置是哪里?有更好的方法来实现AccessToken的设置吗?


你尝试过使用 Using (SqlConnection connection = new SqlConnection()) { } 吗? - GuidoG
由于我在那一点注册了上下文,如果在那里使用了using语句,它会在使用SqlConnection之前将其处置。@GuidoG - ccjx
2个回答

4

您可以先像平常一样将上下文注册:

services.AddDbContext<MainContext>(builder => 
               builder.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

根据文档,默认情况下将其注册为“Scoped”,因此连接将在每个请求上自动打开和关闭。

默认情况下,AddDbContext扩展方法将DbContext类型注册为作用域生命周期。

然后,检索已注册的上下文并按以下方式添加访问令牌:
services.AddScoped<MainContext>(serviceProvider => {
      var dbContext = serviceProvider.GetRequiredService<MainContext>();  
      var connection = dbContext.Database.GetDbConnection() as SqlConnection;
      if(connection == null) {
          return dbContext;
      }
      connection.AccessToken = (new AzureServiceTokenProvider()).GetAccessTokenAsync("https://database.windows.net/").Result;
      return dbContext;
});

现在,在每个请求中,连接将被自动创建并处理,然后访问令牌将被检索。
另一种方式(可能更加干净),是通过继承您的上下文并在构造函数中添加令牌:
public class ContextWithAccessToken : MainDbContext 
{
    public ContextWithAccessToken(DbContextOptions options) : base(options)
    {
        var connection = (SqlConnection)this.Database.GetDbConnection();
        connection.AccessToken = (new AzureServiceTokenProvider()).GetAccessTokenAsync("https://database.windows.net/").Result;
    }
}

然后只需注册此上下文即可:
services.AddDbContext<ContextWithAccessToken>(builder => 
               builder.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

谢谢您的快速响应,让我来看看。我喜欢您创建子类上下文来封装它,而不是向Startup类添加更多代码。 - ccjx
我不确定ContextWithAccessToken是一个很好的选择。所有的配置都从它应该被配置的类中移动到了类本身;在这个过程中,使得对DbContext进行模拟/单元测试更加困难,因为它现在在构造函数中有一个内部依赖项?至少,AzureServiceTokenProvider应该被注入到构造函数中,以允许它被模拟,并遵循IOC模式。 - Robert Perry
我提出了两个选项,使用 DI 或继承。DbContext 仍然可以被模拟。 - Isma

-1

你不需要手动释放连接。它已经与 DbContext 相关联/配置,并且上下文会管理处理。你的代码应该可以正常工作。


不,他的配置方式不会自动释放连接,如果你创建了它,就要手动释放它;-) - Isma
我最初认为是因为我没有在SqlConnection上执行“.Open()”。但我相信它可能有底层资源,如需要处理的连接池。 - ccjx

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接