0

I have a asp.net core application leveraging Azure SQL via the User Assigned ManagedIdentity created using Azure portal.

In this implementation I am using Microsoft.EntityFrameworkCore version 2.2.6

I have the following code :

IDBAuthTokenService.cs

public interface IDBAuthTokenService
{
    Task<string> GetTokenAsync();
}

AzureSqlAuthTokenService.cs

public class AzureSqlAuthTokenService : IDBAuthTokenService
{
    public readonly IConfiguration _configuration;
    public AzureSqlAuthTokenService(IConfiguration configuration)
    {
        _configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
    }

    public async Task<string> GetTokenAsync()
    {
        var credential = new DefaultAzureCredential(new DefaultAzureCredentialOptions{ManagedIdentityClientId = _configuration[C.AppKeys.UserAssignedClientId]});
        var tokenRequestContext = new TokenRequestContext(new[]{_configuration[C.AppKeys.AzureSQLResourceId]});
        var token = await credential.GetTokenAsync(tokenRequestContext, default);
        return token.Token;
    }
}

TestDbContext.cs:

public partial class TestDbContext : DbContext
{
    public TestDbContext()
    {
    }

    public TestDbContext(IDBAuthTokenService tokenService, DbContextOptions<TestDbContext> options) : base(options)
    {
        var connection = this.Database.GetDbConnection() as SqlConnection;
        connection.AccessToken = tokenService.GetTokenAsync().Result;
    }

    public virtual DbSet<HealthCheckData> HealthCheckData { get; set; }
}

Startup.cs

public class Startup
{
    private readonly IConfiguration configuration;
    private readonly IWebHostEnvironment webHostEnvironment;
    /// <summary>
    /// Initializes a new instance of the <see cref = "Startup"/> class.
    /// </summary>
    /// <param name = "configuration">The application configuration, where key value pair settings are stored. See
    /// http://docs.asp.net/en/latest/fundamentals/configuration.html</param>
    /// <param name = "webHostEnvironment">The environment the application is running under. This can be Development,
    /// Staging or Production by default. See http://docs.asp.net/en/latest/fundamentals/environments.html</param>
    public Startup(IConfiguration configuration, IWebHostEnvironment webHostEnvironment)
    {
        this.configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
        this.webHostEnvironment = webHostEnvironment ?? throw new ArgumentNullException(nameof(webHostEnvironment));
    }

    /// <summary>
    /// Configures the services to add to the ASP.NET Core Injection of Control (IoC) container. This method gets
    /// called by the ASP.NET runtime. See
    /// http://blogs.msdn.com/b/webdev/archive/2014/06/17/dependency-injection-in-asp-net-vnext.aspx
    /// </summary>
    /// <param name = "services">The services.</param>
    public virtual void ConfigureServices(IServiceCollection services) => services.AddAppDBConfiguration(configuration, webHostEnvironment)
    /// <summary>
    /// Configures the application and HTTP request pipeline. Configure is called after ConfigureServices is
    /// called by the ASP.NET runtime.
    /// </summary>
    /// <param name = "app">The application builder.</param>
    /// <param name = "l10nIniService">l10nIniService service</param>
    public void Configure(IApplicationBuilder app, L10NCacheInitializationService l10nIniService)
    {
        string loglevel = this.configuration["Logging:LogLevel:Default"] ?? "None";
        _ = Enum.TryParse(loglevel, out LogLevel loglevelEnum);
        app.UseIf(this.webHostEnvironment.IsDevelopment(), x => x.UseServerTiming());
    }
}

CustomServiceCollectionExtensions.cs

public static IServiceCollection AddAppDBConfiguration(this IServiceCollection services, IConfiguration configuration, IWebHostEnvironment webHostEnvironment) => services.AddEntityFrameworkSqlServer().AddDbContextPool<TestDbContext>(appDbContext =>
{
    var appDataDBconn = configuration[VaultKeys.DataDBConnString];
    if (webHostEnvironment.IsEnvironment(Constants.Local))
    {
        appDataDBconn = configuration.GetSection(nameof(ApplicationOptions.Local)).Get<Local>().LocalDataDBConn;
    }

    appDbContext.UseSqlServer(appDataDBconn, sqlServerOptionsAction: sqlOptions =>
    {
        sqlOptions.EnableRetryOnFailure(maxRetryCount: 10, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null);
    });
});

On running the above code I see the below error :

The DbContext of type 'TestDbContext' cannot be pooled because it does not have a single public constructor accepting a single parameter of type DbContextOptions.

Can anyone help me to resolve this issue?

santosh kumar patro
  • 7,231
  • 22
  • 71
  • 143
  • 1
    Why are you using such an outdated version of EF Core? We're on EF Core 6 now. – Dai Jul 08 '22 at 20:42
  • Thanks @Dai for your reply. It is a old existing project at this point of time under maintenance. – santosh kumar patro Jul 08 '22 at 20:46
  • Did you try to remove the default constructor in DbContext Class? If you have any public constructors apart from one that accepts DbContextOptions, you need to remove it to use context pooling. – Pablo Claus Jul 08 '22 at 21:17
  • Error says "single public constructor". You have two constructors. Either remove one or make one private. – jdweng Jul 08 '22 at 21:20

0 Answers0