【问题标题】:ASP.NET Core 3 Dependency Injection - Data Access / Business Layer Class LibraryASP.NET Core 3 依赖注入 - 数据访问/业务层类库
【发布时间】:2020-11-05 05:45:12
【问题描述】:

对 DI 和概念非常陌生,因此我正在努力寻找解决以下问题的方法:

我们有一个 Web 项目(MVC,Core 3)和一个类库(用于所有业务和数据层)。我们试图在类库中有一个 DBContext 类来处理所有数据库连接(使用连接字符串)。我们可以将 IConfiguration 注入到这个 DBContext 中,这样我们就可以从中提取连接字符串并将其放入本地只读字符串中。我们有一个方法可以使用这个连接字符串返回 SQL 连接。

问题是当我们在业务类中时,我们需要访问 DBContext 类来获取 SQL Connection 对象。我们无法创建“新”DBContext,因为我们在其他业务类中没有 IConfigration。

DBContext 类库:

public class DBContext
{
    private readonly string _connectionString;
    private readonly IConfiguration _configuration;

    public DBContext(IConfiguration configuration)
    {
        _configuration = configuration;
        _connectionString = configuration.GetConnectionString("db");
    }

    public SqlConnection Connection()
    {
        return new System.Data.SqlClient.SqlConnection(_connectionString);
    }
}

所以问题出在我们查看类库中的 Customer 类时:

客户类别:

public class Customer
{

    public int CustomerId { get; set; }
    public string CustomerName { get; set; }


    public Customer(int customerId)
    {
        //load customer from the db from the id

        using (IDbConnection db = new DBContext().Connection())
        {
            //call SQL Stored Procedure here ....
        }

    }

}

我们无法创建“新”DBContext 来访问连接,因为在 Customer 类中我们没有要传递给构造函数的 IConfiguration 对象。

我们如何以“正确”的方式实现这一目标?

是否像必须将 IConfiguration 对象 DI 到每个类库构造函数中一样糟糕,例如来自所有 Web 控制器的客户,所以我们可以将其传递给 DBContext?因为这看起来很啰嗦。

对不起,如果这是非常基本的 DI 东西,但只是在努力寻找如何做这些东西的好例子。

提前致谢,

【问题讨论】:

  • 如果您的 Customer 类与数据库本身一起工作,则必须将依赖项注入其中才能与数据库一起工作。注意:它可以只是一个连接字符串,而不是 IConfiguration。
  • 一般来说,要遵守 SOLID 原则,Customer 类必须只执行业务逻辑。存储库类应该与数据库一起使用。

标签: asp.net asp.net-core dependency-injection


【解决方案1】:
public class Customer
{
    private readonly ApplicationDbContext _context;
    public int CustomerId { get; set; }
    public string CustomerName { get; set; }


    public Customer(ApplicationDbContext context, int customerId)
    {
        _context = context; //use _context to reference the db context.
        //do stuff
    }

}

并且在 Startup.cs -> ConfigureServices() 方法中:

services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DevDb")));

为 Dapper 编辑:

在 appsettings.json 中:

"ConnectionStrings": {  
    "DefaultConnection": "<connection string here>"  
  }  

然后在解决方案中添加一个名为 ConnectionString 的类。我们将使用这个类来保存配置文件中的连接字符串值,并通过依赖注入在我们的类中使用它。

public sealed class ConnectionString  
{  
    public ConnectionString(string value) => Value = value;  
  
    public string Value { get; }  
}  

然后在Startup.cs的ASP.NET Core依赖注入容器中注册配置

var connectionString = new ConnectionString(Configuration.GetConnectionString("DefaultConnection"));  
services.AddSingleton(connectionString); 

然后添加你的存储库类:

using Dapper;  
  
public class MovieRepository
{  
    private readonly ConnectionString _connectionString;  
  
    public MovieRepository(ConnectionString connectionString)  
    {  
        _connectionString = connectionString;  
    }  
  
    public async Task<IEnumerable<MovieModel>> GetAllMovies()  
    {  
        const string query = @"SELECT m.Id, m.Name,d.Name AS DirectorName, m.ReleaseYear  
                                FROM Movies m  
                                INNER JOIN Directors d  
                                ON m.DirectorId = d.Id";  
  
        using (var conn = new SqlConnection(_connectionString.Value))  
        {  
            var result = await conn.QueryAsync<MovieModel>(query);  
            return result;  
        }  
    }  
}  

然后在您的 DI 容器中注册 Repository 类。将以下代码添加到 ConfigureServices 方法中。

services.AddScoped<MovieRepository>();  

添加控制器类 MoviesController.cs 并编写一个操作方法以使用此 MovieRepository 获取所有电影。

[ApiController]  
public class MoviesController : ControllerBase  
{  
    private readonly MovieRepository _movieRepository;  
  
    public MoviesController(MovieRepository movieRepository)  
    {  
        _movieRepository = movieRepository;  
    }  
  
    [HttpGet("api/movies")]  
    public async Task<IActionResult> GetMovies()  
    {  
        return Ok(await _movieRepository.GetAllMovies());  
    }  
}  

在此示例中,您的 ApplicationDbContext 等效于电影存储库。答案来自:https://www.c-sharpcorner.com/article/using-dapper-for-data-access-in-asp-net-core-applications/

【讨论】:

  • 感谢您的快速回复。在 startup.cs 我没有 service.AddDbContext。只是提到我没有使用实体框架。如果这有什么不同,在 DAL 中对所有数据库调用使用 Dapper?
  • 谢谢凯文。读了几遍后,我认为这是有道理的。这与我们习惯的做事方式完全不同。所以每个“类型”都会有一个单独的存储库,例如customer、Product、Supplier 和这些每个都在构造函数中使用一个 connectionString。这些通过使用 DI 的 startup.cs 连接到 Web 项目,然后每个控制器在其构造函数 (DI) 中输入它们的存储库。然后我们调用该类型的存储库方法,例如CustomerController 已注入 CustomerRepository,然后调用 CustomerRepository 方法,例如获取、创建、列出等
猜你喜欢
  • 2023-03-11
  • 2021-11-28
  • 1970-01-01
  • 1970-01-01
  • 2010-10-02
  • 2015-01-26
  • 1970-01-01
  • 1970-01-01
  • 2014-02-25
相关资源
最近更新 更多