This article provides the basic setup required to use Dapper with .NET's dependency injection. This example uses this table:
which has this corresponding C# model in the project's
Step 1. Add the Dapper and Microsoft.Data.SqlClient Nuget packages to your project.
Dapper is a performant and lean alternative to Entity Framework. The basic package works very well and there are a slew of Dapper extensions to expand its capabilities.
Microsoft.Data.SqlClient is an improved version of the old
System.Data.SqlClient. It is mostly call-level compatible with
System.Data.SqlClient but there are some differences in "less-used" APIs. See the porting sheet for more information.
Step 2. Add a SQL Server connection string to the
Figure 1. Add a connection string to the
Step 3. Create a
Repository folder in the root of your app. Add this
DapperConnectionProvider class to that folder
Figure 2. The
DapperConnectionProvider does not provide a database connection, rather it provides access the
Microsoft.Data.SqlClient.SqlConnection object. You'll see in a moment how and where the database connection is established.
Step 4. Add a repository interface
Conical use of dependency injection suggests that you inject interfaces so that it's easy to later swap out concrete class implementations. In theory, this would allow you to easily swap out one database for another (eg, swap out a SQL Server-specific repository for one that uses SQLite).
We'll use an interface first here, but will soon revisit this topic. The repository interface defines data access methods. This example has one method, which returns an
IEnumerable list of
Tag objects. Add this interface to the project's
Figure 3. The
Step 5. Add the concrete implementation of the
AppRepository class to your project's
Repository folder. It provides the concrete implementation of the
IAppInterface. See the Dapper docs for help understanding the code in the
AppRepository class's constructor pulls in the
DapperConnectionProviderinstance. This is the first of two dependency injections that occur with this example. We'll later see how .NET injects the
AppRepository class into a controller.
Figure 4. The
The class above uses C#'s new raw literals. This literal type is included in C# 11 but for C# 10 you need to include the line below in the
<PropertyGroup>section of your project's
Step 6. Add the services to the
builder instance in the project's
These lines make the
DapperConnectionProvider and the
AppRepository classes injectable.
Figure 5. Add the two Dapper-related services.
When used as an injected service, Dapper doesn't have a direct analog to the Entity Framework's
DBContext is a scoped instance (that is an instance of ER's
DBContext exists across the duration of a single request) that encapsulates both the database connection and its operations.
In this example, the
DapperConnectionProvider is a singleton instance that provides injectable access to the
Microsoft.Data.SqlClient object. During a request,
DapperConnectionProvider is injected into the
AppRepository, which is a scoped instanced (like the ER's
DBContext). Data access methods in the
AppRepository use the database object provided by the
DapperConnectionProvider to connect to (and dispose) the database connection as needed.
Step 7. Put the code to work
An example controller with Dapper injected is shown below. The controller's constructor pulls in the concrete instance of
IAppREpository (as shown in Step 6).
Figure 6. A controller using the injected Dapper service.
Is it worth the effort to create an interface for the repository?
At the risk of invoking purist ire, I don't think it is in many cases. For my money, using a repository interface is an example of premature optimization and YAGNI. The cost of refactoring a concrete class into an interface/implementation scheme after the app is working is much lower than creating the interface and the class as the app is being developed--especially given that Visual Studio can very easily generate an interface from a concrete class for you.
In the real world, how many times have you ever moved a production application to a different database platform?
If you prefer to create the interface as you develop the app, have it at! Otherwise, make these three changes to the code above to do the work above without the repository interface:
Change 1. Remove the
IAppRepository implementation from the
This is easily done by removing
: IAppRepository from the
AppRepository class declaration.
Change this line:
See Step 5's code above for full comparison.
Change 2. Change the
program.cs class to inject the
AppRepository concrete instance
Change this line:
See Step 6's code above for full comparison.
Change 3. Change the controller's constructor
Change the controller's constructor to have the
AppRepository injected, not the
See Step 7's code above for full comparison.
With these changes, you can remove the