I am trying to understand how to use Dependency Injection with Dapper (IDbConnection) and still being able to use built in dispose.
I have found a couple of articles on the web but non that I think is easy to understand.
What I am trying to figure out is how to make this simple class be testable:
public class UserProfileRepository : IUserProfileRepository
{
private readonly IConfigRepository _configRepository;
public UserProfileRepository(IConfigRepository configRepository)
{
_configRepository = configRepository;
}
public UserProfile GetUserProfile(string userId)
{
const string query = @"Select UserId, UserName
From Users
Where UserId = @UserId";
using (var conn = new SqlConnection(_configRepository.GetConnectionString("MyConnectionString")))
{
conn.Open();
return conn.Query<UserProfile>(query, new { UserId = userId }).SingleOrDefault();
}
}
}
I have a config repository that looks like this so I can mock the request to web.config away:
public class ConfigRepository : IConfigRepository
{
public string GetConnectionString(string key)
{
var conString = ConfigurationManager.ConnectionStrings[key];
if (conString != null)
{
return conString.ConnectionString;
}
return string.Empty;
}
}
I have read that you could use ConnectionFactory but has not figur out how to implement it and still know I am disposing it correct.
Can anyone point me in the right direction?
Best connection creation mechanism as per my experience is the combination of DependencyInjection
and ConnectionFactory
. I am getting rid of IConfigRepository
, since here all the work is done using factory
Advantages are Multi fold:
What you shall do (in Code):
Declare the IDBConnection
object in the Data access Layer:
[Inject] // Property Injection
public IDBConnection Connection {get; set;}
Declare the binding using a DI framework like Ninject:
Bind<IDBConnection>().ToMethod(ctx =>
ConnectionFactory.CreateDbConnection("DefaultConnection"));
Create the DBConnection Factory as follows:
Connection factory fetches the Connection provider and connection string from the config file as follows:
<connectionStrings>
<add name="DefaultConnection" connectionString="Data Source=<Value>;Initial Catalog=<Value>;User Id=<Value>;Password=<Value>" providerName="System.Data.SqlClient" />
</connectionStrings>
Identifier is DefaultConnection
, which is using the SqlClient provider, but at run time can be changed to the different client like Oracle, MySql
using System;
using System.Data.Common;
public static class ConnectionFactory
{
/// <summary>
/// Create DBConnection type based on provider name and connection string
/// </summary>
/// <param name="connectionIdentifier"></param>
/// <returns></returns>
public static DbConnection CreateDbConnection(string connectionIdentifier)
{
// Provider name setting
var providerNameValue = ConfigurationManager.ConnectionStrings[connectionIdentifier].ProviderName;
// Connection string setting
var connectionStringValue = ConfigurationManager.ConnectionStrings[connectionIdentifier].ConnectionString;
// Assume failure.
DbConnection connection;
// Null connection string cannot be accepted
if (connectionStringValue == null) return null;
// Create the DbProviderFactory and DbConnection.
try
{
// Fetch provider factory
var factory = DbProviderFactories.GetFactory(providerNameValue);
// Create Connection
connection = factory.CreateConnection();
// Assign connection string
if (connection != null)
connection.ConnectionString = connectionStringValue;
}
catch (Exception ex)
{
connection = null;
}
// Return the connection.
return connection;
}
}
How to use it:
For a single call and dispose
using(Connection)
{
...
}
For a Transaction context, use as-is, no using
required
Regarding Mocking:
Which ever Mock framework you use for the Unit testing you have to mock the result of the UserProfileRepository :: GetUserProfile(string userId)
, this would be easier instead of filling a MockConnection
using dependency Injection, which will make it complex. DI is good for real use case, for filling connection object at runtime
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With