ASP.NET Core 中的通用存储库,Startup.cs 中的每个表没有单独的 AddScoped 行?
Posted
技术标签:
【中文标题】ASP.NET Core 中的通用存储库,Startup.cs 中的每个表没有单独的 AddScoped 行?【英文标题】:Generic repository in ASP.NET Core without having a separate AddScoped line per table in Startup.cs? 【发布时间】:2015-11-06 11:44:32 【问题描述】:我的项目中有一个通用存储库。 考虑以下控制器 sn-p
public class Lookup1Controller : Controller
readonly MyDbContext _db;
public Lookup1Controller(MyDbContext dataContext)
_db = dataContext;
public async Task<IActionResult> Index()
IGenericRepository<Lookup1> _repository = new GenericRepository<Lookup1>(_db);
var lookup1s = await _repository.SelectAll();
return View(lookup1s);
我认为没有必要在我的通用存储库和每个控制器中都有我的数据库引用。
我将其重构为:
public class Lookup1Controller : Controller
private IGenericRepository<Lookup1> _repository;
public Lookup1Controller(IGenericRepository<Lookup1> repository)
_repository = repository;
public async Task<IActionResult> Index()
var lookup1s = await _repository.SelectAll();
return View(lookup1s);
从我阅读的内容来看,这是更简洁的 ASP.NET 5 最佳实践。 但如果我在浏览器中访问该控制器路由,我会收到以下错误:
InvalidOperationException: Unable to resolve service for type 'MyProject.Data.IGenericRepository`1[MyProject.Models.Lookup1]' while attempting to activate 'MyProject.Controllers.Lookup1.
因为我还没有注入 GenericRepository 来使用接口。
我在ConfigureServices
方法中为我的每个表添加了AddScoped
行
services.AddScoped<IGenericRepository<Lookup1>,GenericRepository<Lookup1>> ();
services.AddScoped<IGenericRepository<Lookup2>,GenericRepository<Lookup2>> ();
services.AddScoped<IGenericRepository<Lookup3>,GenericRepository<Lookup3>> ();
services.AddScoped<IGenericRepository<Lookup4>,GenericRepository<Lookup4>> ();
etc
这样我的代码运行时不会抛出异常。
但是我的数据库有大约 100 个简单的查找表。当我查看上面的 100 行代码时,它看起来并不正确。
感觉就像复制和粘贴代码。每次我通过添加带有视图的新模型和控制器来添加新表时,我的代码都会编译而不会出现错误。但是,如果我运行程序并转到该视图,如果我忘记将 AddScoped 行添加到我的Startup.cs
,我可能会收到控制器运行错误。可维护性不是很好。
我的问题:
在Startup.cs
的ConfigureServices
方法中为每个查找表添加一个service.AddScoped 真的是最佳实践吗?
这是一个通用存储库,所以没有办法将这 100 行复制和粘贴行写在一行中吗?
如果不是,那么使用我的代码执行此操作的最佳做法是什么?
【问题讨论】:
您使用Lookup1Controller
的构造函数和IGenericRepository<Lookup1>
作为参数:public Lookup1Controller(IGenericRepository<Lookup1> repository)
。因此,您期望 MVC 调用带有相应参数的控制器构造函数Lookup1Controller
。谁应该制作new GenericRepository<Lookup1>>()
?应该这样做一次还是每次调用Index
操作?因此,您可以在 services.AddTransient
、services.AddScoped
、services.AddSingleton
和 services.AddInstance
之间进行选择。
这是一个基本的 CRUD 系统。所以有创造。更新、删除方法我省略了。使用 AddScoped 似乎是执行此操作的标准方法,请参阅:wildermuth.com/2015/3/17/A_Look_at_ASP_NET_5_Part_3_-_EF7。如果有更好的方法请分享。
【参考方案1】:
只需使用非泛型注册重载(您需要传递 2 个Type
对象的地方。)然后提供您的接口和实现的open generic types:
services.AddScoped(typeof(IGenericRepository<>), typeof(GenericRepository<>));
在您的控制器中,为特定类型(封闭的泛型)的存储库添加依赖项:
public HomeController(IGenericRepository<Lookup1> repository)
...
【讨论】:
谢谢。更改一行代码有效。对于 ASP.net 5 应用程序或提供替代方案是否是好的做法,将等待看看其他人是否提供意见 这对我不起作用。我收到此错误:失败:Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware[0] 发生未处理的异常:尝试激活“SqlExpress.Helpers.LessonTagHelper”时无法解析类型“SqlExpress.Repository.Interfaces.IChatRepository”的服务。 System.InvalidOperationException:尝试激活“SqlExpress.Helpers.LessonTagHelper”时,无法解析“SqlExpress.Repository.Interfaces.IChatRepository”类型的服务。在... 如果其他人有同样的问题,我在启动应用程序时会因为这个错误而大发雷霆:无法为服务类型 IRepo1[T]' 实例化实现类型 Repo1[T]'。' - 发生这种情况是因为我的 Repo 实现被标记为抽象,我可以通过简单地删除抽象声明来修复它。 @jmdon 谢谢!我快要失去理智了……这就是我在喝咖啡之前进行重构所得到的。对于其他偶然发现这一点的人,请确保如果您将抽象更改为具体,它具有公共构造函数,顺便说一句。我的基础 repo 被提升为具体的泛型有一个受保护的 ctor,它也会在注入尝试时死亡。 如果它对任何人有帮助,我开始看到这一点,因为 Jetbrains Rider 建议我将我的 GenericRepository 构造函数从 public 更改为 protected,我没有考虑就这样做了..【参考方案2】:如果您想在 Assembly 中注册所有 IGenericRepository<>
实现:
services.AddAllGenericTypes(typeof(IGenericRepository<>), new[] typeof(MyDbContext).GetTypeInfo().Assembly);
扩展名来自: https://gist.github.com/GetoXs/5caf0d8cfe6faa8a855c3ccef7c5a541
【讨论】:
以上是关于ASP.NET Core 中的通用存储库,Startup.cs 中的每个表没有单独的 AddScoped 行?的主要内容,如果未能解决你的问题,请参考以下文章
如何从 ASP.NET Core 3.1 中的存储库类创建确认电子邮件回调
ASP.NET Core API 控制器方法中的存储库结果和状态代码
如何按照存储库模式在 Asp.Net Core 5.0 项目上实现 .Net Core Identity?
asp.net core, Ef core : 在运行时动态映射存储库和服务