关于如何将Dapper与Structuremap和依赖注入一起使用的简单但很好的示例

时间:2016-10-27 19:09:45

标签: c# dependency-injection structuremap dapper

我试图了解如何在Dapper(IDbConnection)中使用依赖注入,并且仍然可以使用内置的dispose。

我在网上发现了一些文章,但我觉得很容易理解。

我想弄清楚的是如何使这个简单的类成为可测试的:

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();
        }
    }
}

我有一个看起来像这样的配置存储库,所以我可以模拟对web.config的请求:

public class ConfigRepository : IConfigRepository
{
    public string GetConnectionString(string key)
    {
        var conString = ConfigurationManager.ConnectionStrings[key];
        if (conString != null)
        {
            return conString.ConnectionString;
        }

        return string.Empty;
    }
}

我已经读过你可以使用ConnectionFactory但是没有弄清楚如何实现它,但仍然知道我正在处理它。

有人能指出我正确的方向吗?

1 个答案:

答案 0 :(得分:4)

根据我的经验,最佳连接创建机制是DependencyInjectionConnectionFactory的组合。我摆脱了IConfigRepository,因为这里所有的工作都是使用工厂完成的

优势是多重的:

  • 在事务或线程范围内的运行时创建连接对象
  • 在运行时更改数据提供者,从而更改系统数据库(使用连接工厂)

你将做什么(在代码中):

在数据访问层中声明IDBConnection对象:

[Inject] // Property Injection
public IDBConnection Connection {get; set;}

使用像Ninject这样的DI框架声明绑定:

Bind<IDBConnection>().ToMethod(ctx => 
ConnectionFactory.CreateDbConnection("DefaultConnection"));

按如下方式创建DBConnection Factory:

连接工厂从配置文件中获取连接提供程序和连接字符串,如下所示:

<connectionStrings>
    <add name="DefaultConnection" connectionString="Data Source=<Value>;Initial Catalog=<Value>;User Id=<Value>;Password=<Value>" providerName="System.Data.SqlClient" />
</connectionStrings>

标识符为DefaultConnection,它使用的是SqlClient提供程序,但在运行时可以更改为不同的客户端,如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;
        }
}

如何使用它:

进行一次通话并处理

using(Connection)
{
 ...
}

对于交易上下文,按原样使用,不需要using

关于模拟:

您使用哪个Mock框架进行单元测试,您必须模拟UserProfileRepository :: GetUserProfile(string userId)的结果,这将更容易,而不是使用依赖注入填充MockConnection,这将使其变得复杂。 DI适用于实际用例,用于在运行时填充连接对象