TLDR: What are the reasons for injecting a connection factory vs the IDbConnection itself.
I'm currently using Autofac in .net MVC to inject an instance of IDbConnection into my repository classes to use with Dapper like so:
Autofac setup:
builder.Register<IDbConnection>(ctx => new
SqlConnection(conSettings.ConnectionString)).InstancePerRequest();
Repo:
public ClientRepository(IDbConnection connection)
{
_connection = connection;
}
public async Task<IEnumerable<Client>> GetAsync()
{
string query = "SELECT * FROM Clients";
return (await _connection.QueryAsync<Client>(query)).ToList();
}
This has been working perfectly fine for me so far, but I'm a little worried about connections staying open and not being disposed of.
Every post I find on the topic ends in someone suggesting passing in a connection factory and calling it in a using statement, without really mentioning why my current setup is "bad".
As far as I can tell every request should get it's own IDbConnection where Dapper takes care of opening and closing the connection and Autofac takes care of the disposing.
Is this not the case? Am I missing something?
They way I'm doing this on an ASP.NET Core project (bear with me for a second, I know it's not what you're using but the concept still applies) is injecting the connection string through the repository constructor.
As you will see, I actually inject the IConfiguration object because I need other settings from the configuration file because of other requirements. Just pretend it's the connection string.
Then my repository looks like this (rough example, written off the top of my head so forgive any mistakes I might have made):
public class FooRepository
{
private readonly IConfiguration _configuration;
public FooRepository(IConfiguration configuration)
{
_configuration = configuration
}
private IDbConnection Connection => new SqlConnection(_configuration.GetConnectionString("myConnectionString"));
public Foo GetById(int id)
{
using (var connection = Connection)
{
return connection.QueryFirstOrDefault<Foo>("select * from ...", new {id});
}
}
}
ADO.NET connections are pooled, opening one as needed and then closing it is the way it's usually done. With using you make sure the connections gets closed and disposed - returned to the pool - as soon as you're done, even if an exception gets thrown.
Of course you might want to extract this common code to an abstract superclass, so that you won't need to repeat the name of the connection string in every repository, nor re-implement the Connection property.
Also, as I mentioned in my comment, Dapper is not in charge of opening or closing connections, in fact it fully expects the connection to be open before you can call any of its methods. This is no longer true, sorry.
If you only inject IDbConnection, that means your repository can only use that one connection and you are relying on the IoC to close/dispose of that connection for you. Also, if you need to connect to two different databases, you can't since you only allow one connection to be created here. If you want to run queries in parallel, you can't since you can only have one open call to a single database at a time. Finally, if getting your connection string is a bit harder and isn't straight from a config file (like a KeyVault), then you need to call an outside Async method or something that IoC won't let you do probably.
For me, I always use a factory because I want to close any connection as soon as I'm done with it instead of waiting for IoC to get rid of it. (It feels dirty to allow something outside of the repository to manage database connections.) I want control over which database I'm connecting to (I often have more than 1 DB I have to work with). I occasionally need to run a bunch of different queries in parallel in order to return all the data I need, so I need multiple connections in a single method. I also have to do some logic since we store our connection strings in Azure Key Vault, so I have to do an async call to get that with secret information, which gets a bit complicated, so the Create method on the factory ends up doing a lot of work.
I agree completely that the advice out there seems to be consistently in favor of injecting factories over injecting connections and that it's hard to find much discussion of why.
I think it's fine in straightforward cases to have your container inject the connection itself, which is simple and immediately alleviates 100% of this repetitive boilerplate: using var conn = _connFactory.Make().
But the advantage of having the container inject a factory instead is that it gives you more control over connection creation/lifetime. One common situation where this control really matters is when you want to use TransactionScope. Since it must be instantiated before any connections that you want to participate in the transaction, it doesn't make sense to use a DI container to create connections ahead of time. Daniel Lorenz brought up a couple of other situations where you might want fine control over connection creation in his answer.
If you decided to go the opposite direction (usually not recommended) by using DbConnection.BeginTransaction to manage transactions rather than TransactionScope, then you'd need to share your DbConnection/DbTransaction instances among all the queries/methods/classes involved in the transaction. In that case, injecting connection factories everywhere and letting classes do their own thing would no longer work. A reasonable solution would be to inject either a connection or a connection factory (doesn't really matter which) into a Unit-of-Work type of class and then inject that into your classes with the actual queries in them (Repositories or whatever). If you want to go deep into the weeds on this topic, check out this question.
Related
I have a challenge using AWS Neptune WebSocket connections in lambda.
The problem is whenever an execution context is created even if I register the connection factory as Singleton in DI you will just get another instance for that execution context. With multiple limitations in such a connection like a machine type of your choice with a certain amount of connections and MaxInProcessPerConnection and ConnectionPoolSize, it won't take long enough to start seeing weird errors like System.Net.WebSockets.WebSocketException.
While I implemented some ping-alive connection hack-around it still is not great (and polluting the code too) I thought to somehow use the ILambdaContext by creating a custom inherited type with a static public property where you can access the connection factory and reuse the connections.
My problem is I can't even find anything for C# yet, something similar has been achieved in this Rust runtime GitHub discussion but I can't seem to understand how to translate it to C#.
This is an ASP.NET Core 6 API project running as lambda function.
Any suggestions on where to start will be highly appreciated.
In the video of course CQRS in Practice.
In the Startup.cs code, it has the following code.
public void ConfiureServices(IServiceCollection services)
{
service.AddMvc();
services.AddScoped<UnitOfWork>();
}
However, the code needs to be to services.AddTransient(); because there is no dispose method for UnitOfWork? Why UnitOfWork.dispose() is required for AddScoped?
The lifetime of an object (scoped, transient, singleton), is a wholly separate issue from whether or not the object implements IDisposable.
It is sometimes the case that objects that implement IDisposable are used in Dependency Injection (often because they're external dependencies that have unmanaged resources), but it's not always that way.
AddScoped, in the context of ASP.NET Core, means that for the lifetime of an ASP.NET request, that same object will be used.
AddTransient, in the context of ASP.NET Core, means that every object instantiation -- even during the same HTTP request, will use a new instance of that object.
For your particular problem -- the Unit of Work issue, you're going to want to make sure whatever database you're using is OK with multiple readers and writers before switching to Transient, the reason being if you're using AddTransient, then if you make multiple calls to the database, you're going to open new transactions and (possibly) connections for each call; and there are databases that do not like this very much (Postgres being a shining example).
The lingo we use to talk about that is the Multiple Active Result Sets issue, and each database handles it differently.
Maybe this question has some explanation around but could not find the best solution to this:
I was reading this blog post from Mark Seemann about the captive dependencies and as far as I understand at the end of the post he comes to conclusion never use or at least try to avoid the captive dependencies otherwise there will be troubles (so far is OK). Here is another post from Autofac documentation.
They suggest using captive dependencies only by purpose (when you know what you are doing!). This made me think about a situation I have on my website. I have like 10 services, all of them rely on DbContext for database operations. I think they could easily be registered as InstancePerLifetimeScope if I fix the problem for DbContext not to hold it forever in memory attached to my services. (I am using Autofac in my case). So, I thought a good starting point would be to create all of these as per lifetime instances and the DbContext as instance per request. Then in my services, I would use something like that:
public class MyService
{
private readonly IDbContext _dbContext = DependencyResolver.Current.GetService<IDbContext>();
private MyModel GetMyModel() => Mapper.Map<MyModel>(_dbContext.MyTable.FirstOrDefault());
}
And then in my startup class I have:
builder.RegisterType<ApplicationDbContext>().As<IDbContext>().InstancePerRequest();
builder.RegisterType<MyService>().As<IMyService>().InstancePerLifetimeScope();
Does this pattern work correctly, I mean not keeping the dbContext forever attached to any service, so it will be disposed at the end of the request and if it works, is there any performance issue from this line:
private readonly IDbContext _dbContext = DependencyResolver.Current.GetService<IDbContext>();
compared to constructor injection(There are many invocations from dbContext to database so I am afraid to get IDbContext every time I want to use it because it might be resource consuming) ?
The reason I want dbContext to be instance per request and not instance per dependency is that I have implemented the unit of work pattern on top of the dbContext object.
A normal method in my controller would look like:
public ActionResult DoSth()
{
using(var unitOfWork = UnitOfWorkManager.NewUnitOfWork())
{
//do stuff
try
{
unitOfWork.Commit();
return View();
}
catch(Exception e)
{
unitOfWork.RollBack();
LoggerService.Log(e);
return View();
}
}
}
If this works fine then there is another issue I am concerned of. So, if I can make my services as instances per lifetime (except DbContext), is there any issue to apply async-await on every method inside of the services to make them non-blocking methods. I am asking this if there is any issue using async-await for the dbContext instance, so, for example, I would have something like this:
public async MyModel GetMyModel()
{
var result = //await on a new task which will use dbcontext instance here
return Mapper.Map<MyModel>(result);
}
Any advice or suggestion is much appreciated!
I'd approach the issue from a distance.
There are some architectural choices which can make your life easier. In web development it's practical to design your application to have stateless service layer (all the state is persisted in DB) and to fit the one HTTP request, one business operation principle (in other words one service method for one controller action).
I don't know how your architecture looks (there's not enough info in your post to determine) but chances are it meets the criteria I described above.
In this case it's easy to decide which component lifetime to choose: DbContext and service classes can be transient (InstancePerDependency in terminology of Autofac) or per request (InstancePerRequest) - it doesn't really matter. The point is that they have the same lifetime so the problem of captive dependencies doesn't arise at all.
Further implications of the above:
You can just use ctor injection in your service classes without worries. (Anyway, service locator pattern would be the last option after investigating lifetime control possibilities like lifetime scopes and IOwned<T>.)
EF itself implements the unit of work pattern via SaveChanges which is suitable most of the cases. Practically, you only need to implement an UoW over EF if its transaction handling doesn't meet your needs for some reason. These are rather special cases.
[...] is there any issue to apply async-await on every method inside of the
services to make them non-blocking methods.
If you apply the async-await pattern consistently (I mean all async operations are awaited) straight up to your controller actions (returning Task<ActionResult> instead of ActionResult), there'll be no issues. (However, keep in mind that in ASP.NET MVC 5 async support is not complete - async child actions are not supported.)
The answer, as always, is it depends... This configuration can work if:
Your scopes are created within the request boundary. Is your unit of work creating a scope?
You don't resolve any of your InstancePerLifetimeScope services before creating your scope. Otherwise they potentially live longer than they should if you create multiple scopes within the request.
I personally would just recommend making anything that depends on DbContext (either directly or indirectly) InstancePerRequest. Transient would work as well. You definitely want everything within one unit of work to be using the same DbContext. Otherwise, with Entity Framework's first level cache, you may have different services retrieving the same database record, but operating on different in-memory copies if they're not using the same DbContext. Last update would win in that case.
I would not reference your container in MyService, just constructor inject it. Container references in your domain or business logic should be used sparingly and only as a last resort.
Do you see any benefit in injecting the database connnection string from the Global.asax.cs
class in ASP.NET MVC compared to the method in reading the connection string from a BaseDataProvider class accessing the app.config file?
I'd prefer to inject any objects needed using constructor injection (whenever possible).
One small advantage I see is transparency regarding a class's dependencies.
For example, if you try to instantiate a class in a test harness (while doing integration testing):
in the first case (constructor injection) you immediately see that it needs a connection string and provide one
in the second case you instantiate the class (perhaps using a default constructor) and after some trial & error discover that it depends on the ConnectionString property being set
Update:
Another advantage of the constructor injection approach is that it decouples the class itself from the mechanism of getting the connection string from the app.config.
This could enable in the future scenarios that you don't even think about right now.
For example, in a project I currently work on I have a component that has db access and I have reused it in several contexts. In some of them it uses a standard connection string coming from the config file, while in others I have another component that decides which connection string to use based on some conditions.
If you go for the second approach, you'll need to change the code in order to support such a functionality.
I usually take a hybrid approach such that my BaseDataProvider class has an empty constructor which defaults to whatever is stored in the config, but is overriden to accept a connString for cases where I need a connection other than the default.
Then my Global.asax class contains the necessary logic to determine what connection string they might need in a given situation. For example, say you have your web application deployed internationally on servers all over the world, you'd want to connect to the nearest available db server to avoid latency issues. So on user login, I would figure out where my user was and then set them up with the appropriate connection
There is a long running habit here where I work that the connection string lives in the web.config, a Sql Connection object is instantiated in a using block with that connection string and passed to the DataObjects constructor (via a CreateInstance Method as the constructor is private). Something like this:
using(SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString))
{
DataObject foo = DataObject.CreateInstance(conn);
foo.someProperty = "some value";
foo.Insert();
}
This all smells to me.. I don't know. Shouldn't the DataLayer class library be responsible for Connection objects and Connection strings? I'd be grateful to know what others are doing or any good online articles about these kind of design decisions.
Consider that the projects we work on are always Sql Server backends and that is extremely unlikely to change. So factory and provider pattern is not what I'm after. It's more about where responsibility lies and where config settings should be managed for data layer operation.
I like to code the classes in my data access layer so that they have one constructor that takes an IDbConnection as a parameter, and another that takes a (connection) string.
That way the calling code can either construct its own SqlConnection and pass it in (handy for integration tests), mock an IDbConnection and pass that in (handy for unit tests) or read a connection string from a configuration file (eg web.config) and pass that in.
Hm, I think I agree that the datalayer should be responsible for managing such connection strings so the higher layers don't need to worry about this. However, I do not think that the SQLConnection should worry where the connection string comes from.
I think, I would have a datalayer which provides certain DataInputs, that is, things that take a condition and return DataObjects. Such a DataInput now knows "hey, this DataObjects are stored in THAT Database, and using the Configurations, I can use some connection-string to get an SQL-Connection from over there.
That way you have encapsulated the entire process of "How and where do the data objects come from?" and the internals of the datalayer can still be tested properly. (And, as a side effect, you can easily use different databases, or even multiple different databases at the same time. Such flexibility that just pops up is a good sign(tm))
this being a "smell" is relative. if you are pretty sure about coupling this particular piece of code to SQL Server and a web.config connection string entry then it's perfectly OK. if you are not into this kind of coupling, I agree that it is a code smell and is undesirable.