Injecting a DbContext with an async constructor dependency
Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
1
down vote
favorite
The goal is to construct a DbContext
with a connection that uses an access token. The access token is acquired with ADAL (Active Directory Authentication Library).
The problem is that acquiring an access token is an async operation. Luckily, ADAL uses ConfigureAwait(false)
for its async calls, so it should be safe to do sync-over-async without risking deadlocks.
Full code is provided below. The focus for this question is on the sync-over-async code and method of registering the DbContext
, but remarks for the other code are welcome too.
Container configuration
private Container CreateContainer(AppSettings.Root appSettings)
var container = new Container();
/*
* AsyncScopedLifestyle is recommended for Web API applications.
* https://simpleinjector.readthedocs.io/en/latest/lifetimes.html#asyncscoped-vs-webrequest
*/
container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();
container.Register<ITokenProvider>(
() => new TokenProvider(appSettings.Azure.TenantId, appSettings.Azure.ClientId, appSettings.Azure.ClientCertificateSDN),
Lifestyle.Singleton
);
container.Register<IConnectionFactory, ConnectionFactory>(Lifestyle.Singleton);
container.Register(
() => new FooDbContext(container.GetInstance<IConnectionFactory>().CreateConnection(appSettings.Foo.Database.ConnectionString)),
Lifestyle.Scoped
);
/*
* Calling Verify is not required, but is highly encouraged.
* https://simpleinjector.readthedocs.io/en/latest/using.html#verifying-the-container-s-configuration
*/
container.Verify();
return container;
Token provider
public interface ITokenProvider
Task<string> GetDatabaseAccessToken();
public sealed class TokenProvider
: ITokenProvider
/*
* Asynchronous calls have ConfigureAwait(false) to allow sync-over-async without risking a deadlock, e.g. when a token is required during construction.
* ADAL supports this as per https://github.com/AzureAD/azure-activedirectory-library-for-dotnet/issues/504.
*/
private readonly string tenantId;
private readonly string clientId;
private readonly X509Certificate2 clientCertificate;
public TokenProvider(
string tenantId,
string clientId,
string clientCertificateSDN
)
this.tenantId = tenantId ?? throw new ArgumentNullException(nameof(tenantId));
this.clientId = clientId ?? throw new ArgumentNullException(nameof(clientId));
using (var certificateStore = new X509Store(StoreName.My, StoreLocation.CurrentUser))
certificateStore.Open(OpenFlags.ReadOnly);
this.clientCertificate = certificateStore.Certificates
.Find(X509FindType.FindBySubjectDistinguishedName, clientCertificateSDN ?? throw new ArgumentNullException(nameof(clientCertificateSDN)), false)
[0];
private async Task<string> GetAccessToken(string resource)
var authenticationContext = new AuthenticationContext($"https://login.microsoftonline.com/tenantId");
var clientAssertionCertificate = new ClientAssertionCertificate(this.clientId, this.clientCertificate);
var authenticationResult = await authenticationContext.AcquireTokenAsync(resource, clientAssertionCertificate).ConfigureAwait(false);
return authenticationResult.AccessToken;
public async Task<string> GetDatabaseAccessToken()
return await this.GetAccessToken("https://database.windows.net/").ConfigureAwait(false);
Connection factory
public interface IConnectionFactory
SqlConnection CreateConnection(string connectionString);
public sealed class ConnectionFactory
: IConnectionFactory
private readonly ITokenProvider tokenProvider;
public ConnectionFactory(ITokenProvider tokenProvider)
this.tokenProvider = tokenProvider ?? throw new ArgumentNullException(nameof(tokenProvider));
public SqlConnection CreateConnection(string connectionString)
return new SqlConnection(connectionString)
AccessToken = this.tokenProvider.GetDatabaseAccessToken().Result
;
DbContext
public partial class FooDbContext
: DbContext
public FooDbContext(SqlConnection connection)
: base(connection, false)
c# entity-framework dependency-injection async-await simple-injector
add a comment |Â
up vote
1
down vote
favorite
The goal is to construct a DbContext
with a connection that uses an access token. The access token is acquired with ADAL (Active Directory Authentication Library).
The problem is that acquiring an access token is an async operation. Luckily, ADAL uses ConfigureAwait(false)
for its async calls, so it should be safe to do sync-over-async without risking deadlocks.
Full code is provided below. The focus for this question is on the sync-over-async code and method of registering the DbContext
, but remarks for the other code are welcome too.
Container configuration
private Container CreateContainer(AppSettings.Root appSettings)
var container = new Container();
/*
* AsyncScopedLifestyle is recommended for Web API applications.
* https://simpleinjector.readthedocs.io/en/latest/lifetimes.html#asyncscoped-vs-webrequest
*/
container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();
container.Register<ITokenProvider>(
() => new TokenProvider(appSettings.Azure.TenantId, appSettings.Azure.ClientId, appSettings.Azure.ClientCertificateSDN),
Lifestyle.Singleton
);
container.Register<IConnectionFactory, ConnectionFactory>(Lifestyle.Singleton);
container.Register(
() => new FooDbContext(container.GetInstance<IConnectionFactory>().CreateConnection(appSettings.Foo.Database.ConnectionString)),
Lifestyle.Scoped
);
/*
* Calling Verify is not required, but is highly encouraged.
* https://simpleinjector.readthedocs.io/en/latest/using.html#verifying-the-container-s-configuration
*/
container.Verify();
return container;
Token provider
public interface ITokenProvider
Task<string> GetDatabaseAccessToken();
public sealed class TokenProvider
: ITokenProvider
/*
* Asynchronous calls have ConfigureAwait(false) to allow sync-over-async without risking a deadlock, e.g. when a token is required during construction.
* ADAL supports this as per https://github.com/AzureAD/azure-activedirectory-library-for-dotnet/issues/504.
*/
private readonly string tenantId;
private readonly string clientId;
private readonly X509Certificate2 clientCertificate;
public TokenProvider(
string tenantId,
string clientId,
string clientCertificateSDN
)
this.tenantId = tenantId ?? throw new ArgumentNullException(nameof(tenantId));
this.clientId = clientId ?? throw new ArgumentNullException(nameof(clientId));
using (var certificateStore = new X509Store(StoreName.My, StoreLocation.CurrentUser))
certificateStore.Open(OpenFlags.ReadOnly);
this.clientCertificate = certificateStore.Certificates
.Find(X509FindType.FindBySubjectDistinguishedName, clientCertificateSDN ?? throw new ArgumentNullException(nameof(clientCertificateSDN)), false)
[0];
private async Task<string> GetAccessToken(string resource)
var authenticationContext = new AuthenticationContext($"https://login.microsoftonline.com/tenantId");
var clientAssertionCertificate = new ClientAssertionCertificate(this.clientId, this.clientCertificate);
var authenticationResult = await authenticationContext.AcquireTokenAsync(resource, clientAssertionCertificate).ConfigureAwait(false);
return authenticationResult.AccessToken;
public async Task<string> GetDatabaseAccessToken()
return await this.GetAccessToken("https://database.windows.net/").ConfigureAwait(false);
Connection factory
public interface IConnectionFactory
SqlConnection CreateConnection(string connectionString);
public sealed class ConnectionFactory
: IConnectionFactory
private readonly ITokenProvider tokenProvider;
public ConnectionFactory(ITokenProvider tokenProvider)
this.tokenProvider = tokenProvider ?? throw new ArgumentNullException(nameof(tokenProvider));
public SqlConnection CreateConnection(string connectionString)
return new SqlConnection(connectionString)
AccessToken = this.tokenProvider.GetDatabaseAccessToken().Result
;
DbContext
public partial class FooDbContext
: DbContext
public FooDbContext(SqlConnection connection)
: base(connection, false)
c# entity-framework dependency-injection async-await simple-injector
Can someone with tag creation privileges add thesimple-injector
tag for me? Thanks!
â Stijn
Feb 5 at 12:24
2
It seems yourTokenProvider
class has a dependency on aX509Certificate2
. Is this intended to be lazy loaded? I would probably generate the certificate inside yourCreateContainer
method and add that to the container as a singleton. This way if it fails, it "fails fast" on startup, and potentially other future classes have access to that certificate.
â Brad M
Feb 5 at 14:20
@BradM Good point, the certificate will eventually be used by other parts of the application, so indeed it makes sense to retrieve it in the container. Thanks!
â Stijn
Feb 5 at 14:43
add a comment |Â
up vote
1
down vote
favorite
up vote
1
down vote
favorite
The goal is to construct a DbContext
with a connection that uses an access token. The access token is acquired with ADAL (Active Directory Authentication Library).
The problem is that acquiring an access token is an async operation. Luckily, ADAL uses ConfigureAwait(false)
for its async calls, so it should be safe to do sync-over-async without risking deadlocks.
Full code is provided below. The focus for this question is on the sync-over-async code and method of registering the DbContext
, but remarks for the other code are welcome too.
Container configuration
private Container CreateContainer(AppSettings.Root appSettings)
var container = new Container();
/*
* AsyncScopedLifestyle is recommended for Web API applications.
* https://simpleinjector.readthedocs.io/en/latest/lifetimes.html#asyncscoped-vs-webrequest
*/
container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();
container.Register<ITokenProvider>(
() => new TokenProvider(appSettings.Azure.TenantId, appSettings.Azure.ClientId, appSettings.Azure.ClientCertificateSDN),
Lifestyle.Singleton
);
container.Register<IConnectionFactory, ConnectionFactory>(Lifestyle.Singleton);
container.Register(
() => new FooDbContext(container.GetInstance<IConnectionFactory>().CreateConnection(appSettings.Foo.Database.ConnectionString)),
Lifestyle.Scoped
);
/*
* Calling Verify is not required, but is highly encouraged.
* https://simpleinjector.readthedocs.io/en/latest/using.html#verifying-the-container-s-configuration
*/
container.Verify();
return container;
Token provider
public interface ITokenProvider
Task<string> GetDatabaseAccessToken();
public sealed class TokenProvider
: ITokenProvider
/*
* Asynchronous calls have ConfigureAwait(false) to allow sync-over-async without risking a deadlock, e.g. when a token is required during construction.
* ADAL supports this as per https://github.com/AzureAD/azure-activedirectory-library-for-dotnet/issues/504.
*/
private readonly string tenantId;
private readonly string clientId;
private readonly X509Certificate2 clientCertificate;
public TokenProvider(
string tenantId,
string clientId,
string clientCertificateSDN
)
this.tenantId = tenantId ?? throw new ArgumentNullException(nameof(tenantId));
this.clientId = clientId ?? throw new ArgumentNullException(nameof(clientId));
using (var certificateStore = new X509Store(StoreName.My, StoreLocation.CurrentUser))
certificateStore.Open(OpenFlags.ReadOnly);
this.clientCertificate = certificateStore.Certificates
.Find(X509FindType.FindBySubjectDistinguishedName, clientCertificateSDN ?? throw new ArgumentNullException(nameof(clientCertificateSDN)), false)
[0];
private async Task<string> GetAccessToken(string resource)
var authenticationContext = new AuthenticationContext($"https://login.microsoftonline.com/tenantId");
var clientAssertionCertificate = new ClientAssertionCertificate(this.clientId, this.clientCertificate);
var authenticationResult = await authenticationContext.AcquireTokenAsync(resource, clientAssertionCertificate).ConfigureAwait(false);
return authenticationResult.AccessToken;
public async Task<string> GetDatabaseAccessToken()
return await this.GetAccessToken("https://database.windows.net/").ConfigureAwait(false);
Connection factory
public interface IConnectionFactory
SqlConnection CreateConnection(string connectionString);
public sealed class ConnectionFactory
: IConnectionFactory
private readonly ITokenProvider tokenProvider;
public ConnectionFactory(ITokenProvider tokenProvider)
this.tokenProvider = tokenProvider ?? throw new ArgumentNullException(nameof(tokenProvider));
public SqlConnection CreateConnection(string connectionString)
return new SqlConnection(connectionString)
AccessToken = this.tokenProvider.GetDatabaseAccessToken().Result
;
DbContext
public partial class FooDbContext
: DbContext
public FooDbContext(SqlConnection connection)
: base(connection, false)
c# entity-framework dependency-injection async-await simple-injector
The goal is to construct a DbContext
with a connection that uses an access token. The access token is acquired with ADAL (Active Directory Authentication Library).
The problem is that acquiring an access token is an async operation. Luckily, ADAL uses ConfigureAwait(false)
for its async calls, so it should be safe to do sync-over-async without risking deadlocks.
Full code is provided below. The focus for this question is on the sync-over-async code and method of registering the DbContext
, but remarks for the other code are welcome too.
Container configuration
private Container CreateContainer(AppSettings.Root appSettings)
var container = new Container();
/*
* AsyncScopedLifestyle is recommended for Web API applications.
* https://simpleinjector.readthedocs.io/en/latest/lifetimes.html#asyncscoped-vs-webrequest
*/
container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();
container.Register<ITokenProvider>(
() => new TokenProvider(appSettings.Azure.TenantId, appSettings.Azure.ClientId, appSettings.Azure.ClientCertificateSDN),
Lifestyle.Singleton
);
container.Register<IConnectionFactory, ConnectionFactory>(Lifestyle.Singleton);
container.Register(
() => new FooDbContext(container.GetInstance<IConnectionFactory>().CreateConnection(appSettings.Foo.Database.ConnectionString)),
Lifestyle.Scoped
);
/*
* Calling Verify is not required, but is highly encouraged.
* https://simpleinjector.readthedocs.io/en/latest/using.html#verifying-the-container-s-configuration
*/
container.Verify();
return container;
Token provider
public interface ITokenProvider
Task<string> GetDatabaseAccessToken();
public sealed class TokenProvider
: ITokenProvider
/*
* Asynchronous calls have ConfigureAwait(false) to allow sync-over-async without risking a deadlock, e.g. when a token is required during construction.
* ADAL supports this as per https://github.com/AzureAD/azure-activedirectory-library-for-dotnet/issues/504.
*/
private readonly string tenantId;
private readonly string clientId;
private readonly X509Certificate2 clientCertificate;
public TokenProvider(
string tenantId,
string clientId,
string clientCertificateSDN
)
this.tenantId = tenantId ?? throw new ArgumentNullException(nameof(tenantId));
this.clientId = clientId ?? throw new ArgumentNullException(nameof(clientId));
using (var certificateStore = new X509Store(StoreName.My, StoreLocation.CurrentUser))
certificateStore.Open(OpenFlags.ReadOnly);
this.clientCertificate = certificateStore.Certificates
.Find(X509FindType.FindBySubjectDistinguishedName, clientCertificateSDN ?? throw new ArgumentNullException(nameof(clientCertificateSDN)), false)
[0];
private async Task<string> GetAccessToken(string resource)
var authenticationContext = new AuthenticationContext($"https://login.microsoftonline.com/tenantId");
var clientAssertionCertificate = new ClientAssertionCertificate(this.clientId, this.clientCertificate);
var authenticationResult = await authenticationContext.AcquireTokenAsync(resource, clientAssertionCertificate).ConfigureAwait(false);
return authenticationResult.AccessToken;
public async Task<string> GetDatabaseAccessToken()
return await this.GetAccessToken("https://database.windows.net/").ConfigureAwait(false);
Connection factory
public interface IConnectionFactory
SqlConnection CreateConnection(string connectionString);
public sealed class ConnectionFactory
: IConnectionFactory
private readonly ITokenProvider tokenProvider;
public ConnectionFactory(ITokenProvider tokenProvider)
this.tokenProvider = tokenProvider ?? throw new ArgumentNullException(nameof(tokenProvider));
public SqlConnection CreateConnection(string connectionString)
return new SqlConnection(connectionString)
AccessToken = this.tokenProvider.GetDatabaseAccessToken().Result
;
DbContext
public partial class FooDbContext
: DbContext
public FooDbContext(SqlConnection connection)
: base(connection, false)
c# entity-framework dependency-injection async-await simple-injector
edited Apr 11 at 8:11
t3chb0t
32.1k54195
32.1k54195
asked Feb 5 at 12:20
Stijn
196315
196315
Can someone with tag creation privileges add thesimple-injector
tag for me? Thanks!
â Stijn
Feb 5 at 12:24
2
It seems yourTokenProvider
class has a dependency on aX509Certificate2
. Is this intended to be lazy loaded? I would probably generate the certificate inside yourCreateContainer
method and add that to the container as a singleton. This way if it fails, it "fails fast" on startup, and potentially other future classes have access to that certificate.
â Brad M
Feb 5 at 14:20
@BradM Good point, the certificate will eventually be used by other parts of the application, so indeed it makes sense to retrieve it in the container. Thanks!
â Stijn
Feb 5 at 14:43
add a comment |Â
Can someone with tag creation privileges add thesimple-injector
tag for me? Thanks!
â Stijn
Feb 5 at 12:24
2
It seems yourTokenProvider
class has a dependency on aX509Certificate2
. Is this intended to be lazy loaded? I would probably generate the certificate inside yourCreateContainer
method and add that to the container as a singleton. This way if it fails, it "fails fast" on startup, and potentially other future classes have access to that certificate.
â Brad M
Feb 5 at 14:20
@BradM Good point, the certificate will eventually be used by other parts of the application, so indeed it makes sense to retrieve it in the container. Thanks!
â Stijn
Feb 5 at 14:43
Can someone with tag creation privileges add the
simple-injector
tag for me? Thanks!â Stijn
Feb 5 at 12:24
Can someone with tag creation privileges add the
simple-injector
tag for me? Thanks!â Stijn
Feb 5 at 12:24
2
2
It seems your
TokenProvider
class has a dependency on a X509Certificate2
. Is this intended to be lazy loaded? I would probably generate the certificate inside your CreateContainer
method and add that to the container as a singleton. This way if it fails, it "fails fast" on startup, and potentially other future classes have access to that certificate.â Brad M
Feb 5 at 14:20
It seems your
TokenProvider
class has a dependency on a X509Certificate2
. Is this intended to be lazy loaded? I would probably generate the certificate inside your CreateContainer
method and add that to the container as a singleton. This way if it fails, it "fails fast" on startup, and potentially other future classes have access to that certificate.â Brad M
Feb 5 at 14:20
@BradM Good point, the certificate will eventually be used by other parts of the application, so indeed it makes sense to retrieve it in the container. Thanks!
â Stijn
Feb 5 at 14:43
@BradM Good point, the certificate will eventually be used by other parts of the application, so indeed it makes sense to retrieve it in the container. Thanks!
â Stijn
Feb 5 at 14:43
add a comment |Â
1 Answer
1
active
oldest
votes
up vote
1
down vote
If you don't mind me asking, any reason you want to register the DbContext directly? I know .NET Core seems to want you to do that, but I don't like IoC containers deciding when to leave open or close my DB connections. Insetead, I'd just do IFooDbContextFactory and have that use a "CreateAsync" method. This factory can take your IAppSettings or IDbContextSettings or something to get the connection string. Then you can call the provider async just fine and in your specific code you'd just do:
public class FooDbContextFactory : IFooDbContextFactory
private readonly IFooDbContextSettings _settings;
private readonly ITokenProvider _tokenProvider;
public FooDbContextFactory(IFooDbContextSettings settings, ITokenProvider tokenProvider)
_settings = settings;
_tokenProvider = tokenProvider;
public async Task<FooDbContext> CreateAsync()
var token = await _tokenPRovider.GetToken(...).ConfigureAwait(false);
return new FooDbContext(...);
public class SomeRepository
private reaonly IFooDbContextFactory _factory;
public SomeRepository(IFooDbContextFactory factory)
_factory = factory;
public async Task<ICollection<SomeEntity>> GetSomeList()
using (var context = await _factory.CreateAsync().ConfigureAwait(false))
return await context.Somes().ToListAsync().ConfigureAwait(false);
I don't like IoC containers deciding when to leave open or close my DB connections and they don't if you tell them not to. Four ways to dispose IDisposables in ASP.NET Core or with Autofac you can mark a dependency as ExternallyOwned.
â t3chb0t
Apr 11 at 8:07
People can make mistakes with this configuration. With a factory and using statement there is no question when this gets disposed and you don't have to worry about other applications using this code configure it incorrectlyðÂÂÂ
â Daniel Lorenz
Apr 11 at 20:28
This is a very good argument... to kill every idea because people can make mistakes with just anything :-| With a properly configured DI container I have less worries then by maintaining my own solutions. I like the smiley ;-)
â t3chb0t
Apr 12 at 12:19
I just like having control over my database connections. I know when I'm done so I kill it as soon as I'm done with it.
â Daniel Lorenz
Apr 13 at 12:01
Plus if you are doing calls in parallel you'd need multiple instances of dbcontext since you can't share them. Thus you'd need a factory for that anyway. Plus you can have more control over the configuration on it.
â Daniel Lorenz
Apr 13 at 12:04
add a comment |Â
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
1
down vote
If you don't mind me asking, any reason you want to register the DbContext directly? I know .NET Core seems to want you to do that, but I don't like IoC containers deciding when to leave open or close my DB connections. Insetead, I'd just do IFooDbContextFactory and have that use a "CreateAsync" method. This factory can take your IAppSettings or IDbContextSettings or something to get the connection string. Then you can call the provider async just fine and in your specific code you'd just do:
public class FooDbContextFactory : IFooDbContextFactory
private readonly IFooDbContextSettings _settings;
private readonly ITokenProvider _tokenProvider;
public FooDbContextFactory(IFooDbContextSettings settings, ITokenProvider tokenProvider)
_settings = settings;
_tokenProvider = tokenProvider;
public async Task<FooDbContext> CreateAsync()
var token = await _tokenPRovider.GetToken(...).ConfigureAwait(false);
return new FooDbContext(...);
public class SomeRepository
private reaonly IFooDbContextFactory _factory;
public SomeRepository(IFooDbContextFactory factory)
_factory = factory;
public async Task<ICollection<SomeEntity>> GetSomeList()
using (var context = await _factory.CreateAsync().ConfigureAwait(false))
return await context.Somes().ToListAsync().ConfigureAwait(false);
I don't like IoC containers deciding when to leave open or close my DB connections and they don't if you tell them not to. Four ways to dispose IDisposables in ASP.NET Core or with Autofac you can mark a dependency as ExternallyOwned.
â t3chb0t
Apr 11 at 8:07
People can make mistakes with this configuration. With a factory and using statement there is no question when this gets disposed and you don't have to worry about other applications using this code configure it incorrectlyðÂÂÂ
â Daniel Lorenz
Apr 11 at 20:28
This is a very good argument... to kill every idea because people can make mistakes with just anything :-| With a properly configured DI container I have less worries then by maintaining my own solutions. I like the smiley ;-)
â t3chb0t
Apr 12 at 12:19
I just like having control over my database connections. I know when I'm done so I kill it as soon as I'm done with it.
â Daniel Lorenz
Apr 13 at 12:01
Plus if you are doing calls in parallel you'd need multiple instances of dbcontext since you can't share them. Thus you'd need a factory for that anyway. Plus you can have more control over the configuration on it.
â Daniel Lorenz
Apr 13 at 12:04
add a comment |Â
up vote
1
down vote
If you don't mind me asking, any reason you want to register the DbContext directly? I know .NET Core seems to want you to do that, but I don't like IoC containers deciding when to leave open or close my DB connections. Insetead, I'd just do IFooDbContextFactory and have that use a "CreateAsync" method. This factory can take your IAppSettings or IDbContextSettings or something to get the connection string. Then you can call the provider async just fine and in your specific code you'd just do:
public class FooDbContextFactory : IFooDbContextFactory
private readonly IFooDbContextSettings _settings;
private readonly ITokenProvider _tokenProvider;
public FooDbContextFactory(IFooDbContextSettings settings, ITokenProvider tokenProvider)
_settings = settings;
_tokenProvider = tokenProvider;
public async Task<FooDbContext> CreateAsync()
var token = await _tokenPRovider.GetToken(...).ConfigureAwait(false);
return new FooDbContext(...);
public class SomeRepository
private reaonly IFooDbContextFactory _factory;
public SomeRepository(IFooDbContextFactory factory)
_factory = factory;
public async Task<ICollection<SomeEntity>> GetSomeList()
using (var context = await _factory.CreateAsync().ConfigureAwait(false))
return await context.Somes().ToListAsync().ConfigureAwait(false);
I don't like IoC containers deciding when to leave open or close my DB connections and they don't if you tell them not to. Four ways to dispose IDisposables in ASP.NET Core or with Autofac you can mark a dependency as ExternallyOwned.
â t3chb0t
Apr 11 at 8:07
People can make mistakes with this configuration. With a factory and using statement there is no question when this gets disposed and you don't have to worry about other applications using this code configure it incorrectlyðÂÂÂ
â Daniel Lorenz
Apr 11 at 20:28
This is a very good argument... to kill every idea because people can make mistakes with just anything :-| With a properly configured DI container I have less worries then by maintaining my own solutions. I like the smiley ;-)
â t3chb0t
Apr 12 at 12:19
I just like having control over my database connections. I know when I'm done so I kill it as soon as I'm done with it.
â Daniel Lorenz
Apr 13 at 12:01
Plus if you are doing calls in parallel you'd need multiple instances of dbcontext since you can't share them. Thus you'd need a factory for that anyway. Plus you can have more control over the configuration on it.
â Daniel Lorenz
Apr 13 at 12:04
add a comment |Â
up vote
1
down vote
up vote
1
down vote
If you don't mind me asking, any reason you want to register the DbContext directly? I know .NET Core seems to want you to do that, but I don't like IoC containers deciding when to leave open or close my DB connections. Insetead, I'd just do IFooDbContextFactory and have that use a "CreateAsync" method. This factory can take your IAppSettings or IDbContextSettings or something to get the connection string. Then you can call the provider async just fine and in your specific code you'd just do:
public class FooDbContextFactory : IFooDbContextFactory
private readonly IFooDbContextSettings _settings;
private readonly ITokenProvider _tokenProvider;
public FooDbContextFactory(IFooDbContextSettings settings, ITokenProvider tokenProvider)
_settings = settings;
_tokenProvider = tokenProvider;
public async Task<FooDbContext> CreateAsync()
var token = await _tokenPRovider.GetToken(...).ConfigureAwait(false);
return new FooDbContext(...);
public class SomeRepository
private reaonly IFooDbContextFactory _factory;
public SomeRepository(IFooDbContextFactory factory)
_factory = factory;
public async Task<ICollection<SomeEntity>> GetSomeList()
using (var context = await _factory.CreateAsync().ConfigureAwait(false))
return await context.Somes().ToListAsync().ConfigureAwait(false);
If you don't mind me asking, any reason you want to register the DbContext directly? I know .NET Core seems to want you to do that, but I don't like IoC containers deciding when to leave open or close my DB connections. Insetead, I'd just do IFooDbContextFactory and have that use a "CreateAsync" method. This factory can take your IAppSettings or IDbContextSettings or something to get the connection string. Then you can call the provider async just fine and in your specific code you'd just do:
public class FooDbContextFactory : IFooDbContextFactory
private readonly IFooDbContextSettings _settings;
private readonly ITokenProvider _tokenProvider;
public FooDbContextFactory(IFooDbContextSettings settings, ITokenProvider tokenProvider)
_settings = settings;
_tokenProvider = tokenProvider;
public async Task<FooDbContext> CreateAsync()
var token = await _tokenPRovider.GetToken(...).ConfigureAwait(false);
return new FooDbContext(...);
public class SomeRepository
private reaonly IFooDbContextFactory _factory;
public SomeRepository(IFooDbContextFactory factory)
_factory = factory;
public async Task<ICollection<SomeEntity>> GetSomeList()
using (var context = await _factory.CreateAsync().ConfigureAwait(false))
return await context.Somes().ToListAsync().ConfigureAwait(false);
answered Feb 9 at 21:13
Daniel Lorenz
10610
10610
I don't like IoC containers deciding when to leave open or close my DB connections and they don't if you tell them not to. Four ways to dispose IDisposables in ASP.NET Core or with Autofac you can mark a dependency as ExternallyOwned.
â t3chb0t
Apr 11 at 8:07
People can make mistakes with this configuration. With a factory and using statement there is no question when this gets disposed and you don't have to worry about other applications using this code configure it incorrectlyðÂÂÂ
â Daniel Lorenz
Apr 11 at 20:28
This is a very good argument... to kill every idea because people can make mistakes with just anything :-| With a properly configured DI container I have less worries then by maintaining my own solutions. I like the smiley ;-)
â t3chb0t
Apr 12 at 12:19
I just like having control over my database connections. I know when I'm done so I kill it as soon as I'm done with it.
â Daniel Lorenz
Apr 13 at 12:01
Plus if you are doing calls in parallel you'd need multiple instances of dbcontext since you can't share them. Thus you'd need a factory for that anyway. Plus you can have more control over the configuration on it.
â Daniel Lorenz
Apr 13 at 12:04
add a comment |Â
I don't like IoC containers deciding when to leave open or close my DB connections and they don't if you tell them not to. Four ways to dispose IDisposables in ASP.NET Core or with Autofac you can mark a dependency as ExternallyOwned.
â t3chb0t
Apr 11 at 8:07
People can make mistakes with this configuration. With a factory and using statement there is no question when this gets disposed and you don't have to worry about other applications using this code configure it incorrectlyðÂÂÂ
â Daniel Lorenz
Apr 11 at 20:28
This is a very good argument... to kill every idea because people can make mistakes with just anything :-| With a properly configured DI container I have less worries then by maintaining my own solutions. I like the smiley ;-)
â t3chb0t
Apr 12 at 12:19
I just like having control over my database connections. I know when I'm done so I kill it as soon as I'm done with it.
â Daniel Lorenz
Apr 13 at 12:01
Plus if you are doing calls in parallel you'd need multiple instances of dbcontext since you can't share them. Thus you'd need a factory for that anyway. Plus you can have more control over the configuration on it.
â Daniel Lorenz
Apr 13 at 12:04
I don't like IoC containers deciding when to leave open or close my DB connections and they don't if you tell them not to. Four ways to dispose IDisposables in ASP.NET Core or with Autofac you can mark a dependency as ExternallyOwned.
â t3chb0t
Apr 11 at 8:07
I don't like IoC containers deciding when to leave open or close my DB connections and they don't if you tell them not to. Four ways to dispose IDisposables in ASP.NET Core or with Autofac you can mark a dependency as ExternallyOwned.
â t3chb0t
Apr 11 at 8:07
People can make mistakes with this configuration. With a factory and using statement there is no question when this gets disposed and you don't have to worry about other applications using this code configure it incorrectlyðÂÂÂ
â Daniel Lorenz
Apr 11 at 20:28
People can make mistakes with this configuration. With a factory and using statement there is no question when this gets disposed and you don't have to worry about other applications using this code configure it incorrectlyðÂÂÂ
â Daniel Lorenz
Apr 11 at 20:28
This is a very good argument... to kill every idea because people can make mistakes with just anything :-| With a properly configured DI container I have less worries then by maintaining my own solutions. I like the smiley ;-)
â t3chb0t
Apr 12 at 12:19
This is a very good argument... to kill every idea because people can make mistakes with just anything :-| With a properly configured DI container I have less worries then by maintaining my own solutions. I like the smiley ;-)
â t3chb0t
Apr 12 at 12:19
I just like having control over my database connections. I know when I'm done so I kill it as soon as I'm done with it.
â Daniel Lorenz
Apr 13 at 12:01
I just like having control over my database connections. I know when I'm done so I kill it as soon as I'm done with it.
â Daniel Lorenz
Apr 13 at 12:01
Plus if you are doing calls in parallel you'd need multiple instances of dbcontext since you can't share them. Thus you'd need a factory for that anyway. Plus you can have more control over the configuration on it.
â Daniel Lorenz
Apr 13 at 12:04
Plus if you are doing calls in parallel you'd need multiple instances of dbcontext since you can't share them. Thus you'd need a factory for that anyway. Plus you can have more control over the configuration on it.
â Daniel Lorenz
Apr 13 at 12:04
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f186812%2finjecting-a-dbcontext-with-an-async-constructor-dependency%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Can someone with tag creation privileges add the
simple-injector
tag for me? Thanks!â Stijn
Feb 5 at 12:24
2
It seems your
TokenProvider
class has a dependency on aX509Certificate2
. Is this intended to be lazy loaded? I would probably generate the certificate inside yourCreateContainer
method and add that to the container as a singleton. This way if it fails, it "fails fast" on startup, and potentially other future classes have access to that certificate.â Brad M
Feb 5 at 14:20
@BradM Good point, the certificate will eventually be used by other parts of the application, so indeed it makes sense to retrieve it in the container. Thanks!
â Stijn
Feb 5 at 14:43