如何在 ASP.NET Core MVC 中使用依赖注入设计存储库模式?

Posted

技术标签:

【中文标题】如何在 ASP.NET Core MVC 中使用依赖注入设计存储库模式?【英文标题】:How to design a Repository Pattern with Dependency Injection in ASP.NET Core MVC? 【发布时间】:2017-02-21 00:08:41 【问题描述】:

作为 ASP.NET Core 1.0 MVC 的新手,我决定为 MVC Core 应用程序使用存储库模式;我正在为数据层SampleDbContext 使用 SQL DB,并且我想为我的一些业务实体创建一个 Repository 类。到目前为止,我在startup.csCustomerController.csCustomerRepository.cs 文件中完成了以下操作,其中示例实体是“客户”。

在启动类的ConfigureServices方法中:

public void ConfigureServices(IServiceCollection services)

    services.AddDbContext<SampleDbContext>(options =>
       options.UseSqlServer(Configuration.GetConnectionString("SampleDB")));

在控制器中:

public class CustomerController : Controller


    private SampleDBContext _context;
    private CustomerRepository = new CustomerRepository (new SampleDBContext());

    public CustomerController(SampleDBContext context)
    
        _context = context;
    

在存储库中:

public class CustomerRepository

    private SampleDBContext _context;

    public CustomerRepository(SampleDBContext context)
    
        _context = context;
    

通过这种设计,我将SampleDbContext 作为服务插入startup.cs 一次,然后为每个控制器(接收依赖注入)实例化一个相应的存储库,传递SampleDbContext 的新实例. 数据库上下文的这种重复实例化是多用户环境的良好设计吗? 我想我可以将每个存储库作为服务添加到startup.cs,但这看起来不太好。 请告诉我一个适合我的案例的好的设计实现,或者如果我迷路了,请让我走上正轨。

【问题讨论】:

docs.microsoft.com/en-us/aspnet/core/tutorials/… 【参考方案1】:

可以看simple example如何使用repository模式:

您创建存储库接口:

using System.Collections.Generic;

namespace TodoApi.Models

    public interface ITodoRepository
    
        void Add(TodoItem item);
        IEnumerable<TodoItem> GetAll();
        TodoItem Find(long key);
        void Remove(long key);
        void Update(TodoItem item);
    

然后实现它:

using System;
using System.Collections.Generic;
using System.Linq;

namespace TodoApi.Models

    public class TodoRepository : ITodoRepository
    
        private readonly TodoContext _context;

        public TodoRepository(TodoContext context)
        
            _context = context;
            Add(new TodoItem  Name = "Item1" );
        

        public IEnumerable<TodoItem> GetAll()
        
            return _context.TodoItems.ToList();
        

        public void Add(TodoItem item)
        
            _context.TodoItems.Add(item);
            _context.SaveChanges();
        

        public TodoItem Find(long key)
        
            return _context.TodoItems.FirstOrDefault(t => t.Key == key);
        

        public void Remove(long key)
        
            var entity = _context.TodoItems.First(t => t.Key == key);
            _context.TodoItems.Remove(entity);
            _context.SaveChanges();
        

        public void Update(TodoItem item)
        
            _context.TodoItems.Update(item);
            _context.SaveChanges();
        
    

然后在ConfigureServices中注册:

services.AddSingleton<ITodoRepository, TodoRepository>();

然后注入到Controller中:

namespace TodoApi.Controllers

    [Route("api/[controller]")]
    public class TodoController : Controller
    
        public TodoController(ITodoRepository todoItems)
        
            TodoItems = todoItems;
        
        public ITodoRepository TodoItems  get; set; 
    

【讨论】:

这是设计回购模式的明确答案,谢谢!。如果您使用AddSingleton,您会在多用户环境中遇到问题吗? @GiancarloSierra,对此不确定,请查看文档:docs.microsoft.com/en-us/aspnet/core/fundamentals/… @GiancarloSierra,可能 AddScoped 会更适合存储库。 在某些情况下,您将收到“访问已处置的上下文”:( @ruffin,是的,看起来 ASP.NET Core 不再需要存储库模式:***.com/questions/48874591/…【参考方案2】:

有些人认为 DbContext 本身就是一种存储库模式。如果你想走这条路,你可以在ASP.NET Core and Angular 2下载示例代码。

例如-

public class CustomerController : Controller

    private SampleDBContext _context;

    public CustomerController(SampleDBContext context)
    
        _context = context;
    

    public async Task<IActionResult> Index(int id)
    
        var user = _context.Users.Where(i => i.Id == id).FirstOrDefault();
        ...
    

Startup.cs

public void ConfigureServices(IServiceCollection services)

    services.AddDbContext<SampleDBContext>(options =>
        options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"])
        );

【讨论】:

是的。有些人可能会争辩说 DbContext 遵循工作单元模式:)。我认为实现存储库模式的主要原因是将您的存储框架(即 EntityFramework)与应用程序的其余部分分开。也许应用想稍后存储在文本文件中(不知道为什么,但是,嘿,总是做出疯狂的决定)。 @Win 所以在问题的模型中,我使用与这个答案相同的模型,但我将 DbContext 上的一个新实例传递给每个实体的存储库类。再次陈述我的问题;数据库上下文的这种重复实例化是否适合多用户环境? @GiancarloSierra 不要为每个实体创建新的 DbContext 实例。基本上,Controller 或 CustomerRepository 不应该创建 DbContext 的实例。让 IoC 容器处理它。 @Win,IoC 的观点听起来合乎逻辑。就此而言,我在控制器上使用依赖注入 (DI) 时没有看到问题,因为直接接收到,但是,在发布的场景中,您将如何使用 DI 将 DbContext 传递给 CustomerRepository? 我认为添加此模式可以更轻松地升级到另一个版本更新。 EF 在过去几年中进行了许多更新,因此升级到版本 8 意味着只更新该特定类。【参考方案3】:

我不确定它是最好的方法,但我一直将存储库创建为控制器实现的接口。

IRepository.cs:

public interface IRepository

     SomeList GetSomeList(string userId);
     Some GetSomeDetail(int someId);

DbInterface.cs:

public class DbInterface : IRepository

    public SomeList GetSomeList(string userId)
    

    

    public Some GetSomeDetail(int someId)
    

    

SomeList 是我定义的一种数据类型,其中包含要在页面上显示为列表的所有属性。 IE。任务应用程序中的任务列表。有些是定义的数据类型,它返回 a 任务的详细信息(因此输入将是 taskId 等)。

如果这是一个不好的方法,很高兴得到纠正。

【讨论】:

差不多了,除了我认为你的意思是你创建了一个 IRepository 的具体实现,DbInterface 然后注入到你的控制器中。请参阅@Alex 的回答。 混蛋。忘记了一些步骤。谢谢:)

以上是关于如何在 ASP.NET Core MVC 中使用依赖注入设计存储库模式?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 ASP.NET Core MVC 中使用依赖注入设计存储库模式?

如何在 ASP.NET Core MVC 中使用 ADO.NET 向存储过程添加参数?

如何使用 C# 在 ASP.NET Core 3.1 MVC 中使用会话变量

如何在 ASP.Net Core MVC 中使用 HTML 链接?

使用命令行如何在 ASP.NET 中首先从 DB 搭建脚手架 - 而不是 ASP.NET Core MVC?

使用 ASP.NET Core MVC,如何显示图像?