如何在 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.cs
、CustomerController.cs
和CustomerRepository.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 链接?