c# - C# .Net Core 2 DI,我如何注册一个接口,该接口也采用与构造函数相同的接口作为参数(装饰器)
问题描述
我有一个实现 IRepository 接口的存储库。我创建了一个 CachedRepository ,它也实现了 IRepository 但它采用 IRepository 作为构造函数参数。另外,我知道我最终会创建一个继承 Repository 的 Oracle11Repository 来覆盖一些 Repository 方法。
我的目标是能够在 startup.cs 中交换这 3 个存储库,而无需修改应用程序的其余部分。
如何注册 IRepository 以使用 CachedRepository,指定 CachedRepository 必须像自己的 IRepository 一样使用 Repository?
显然,我收到错误“检测到'IRepository'类型的服务的循环依赖”
或者也许是我的方法不正确?
//Repository.cs
public class Repository : IRepository
{
private readonly IDbConnectionFactory dbFactory;
private readonly ILogger<Repository> logger;
public AssessmentRepository(IDbConnectionFactory dbFactory, ILogger<Repository> logger, IConfiguration configuration)
{
this.dbFactory = dbFactory;
this.logger = logger;
}
public async Task<PagedEnvelope<SearchResult>> Search(string term)
{}
}
//CachedRepository.cs
public class Repository : IRepository
{
private IRepository repos;
private readonly ILogger<Repository> logger;
private IMemoryCache cache;
public CachedREpository(IRepository repos, ILogger<Repository> logger, IMemoryCache cache, IConfiguration configuration)
{
this.repos = repos;
this.logger = logger;
ConfigureCache(cache, configuration);
}
public async Task<PagedEnvelope<SearchResult>> Search(string term)
{
// If not in cache, call repos.Search(term) then cache and return
}
}
//Startup.cs
public void ConfigureServices(IServiceCollection services)
{
//...
services.AddTransient<IRepository, CachedRepository>();
}
解决方案
在我看来,您需要Repository
为您的功能设置一个基类,以及一个基础接口,该接口将使基础与未来注入保持一致,因此可能需要重命名和新接口。所以假设你的数据库是 SQL,你的Repository
类声明会变成
public class SqlRepository : IRepositoryBase
{
// SQL Specific Search Method
}
并且基础存储库接口现在是
public interface IRepositoryBase
{
public Task<PagedEnvelope<SearchResult>> Search(string term);
}
您现在有了一个特定于您的 SQL 访问的实现和一个用于注入的接口,然后您将其注入到您的CachedRepository
类中,如下所示。
public class CachedRepository : IRepository
{
private IRepositoryBase _reposBase;
private IMemoryCache _cache;
public CachedREpository(IRepositoryBase reposBase,
IMemoryCache cache,
IConfiguration configuration)
{
this._reposBase = reposBase;
this._cache = cache;
// Note I took the logger out, you have it in the _reposBase object now.
ConfigureCache(cache, configuration);
}
public async Task<PagedEnvelope<SearchResult>> Search(string term)
{
// If not in cache, call _reposBase.Search(term) then cache and return
}
}
现在在您的Startup
班级中,您可以使用 2 次注入来配置它:
//Startup.cs
public void ConfigureServices(IServiceCollection services)
{
//...
// Set up injection for Base first
services.AddTransient<IRepositoryBase, SqlRepository>();
// Then set up injection for your Cached repo
services.AddTransient<IRepository, CachedRepository>();
}
现在您有了一些内置的灵活性,因为要更改为 Oracle DB,您只需创建 Oracle 存储库库:
public class OracleRepository : IRepositoryBase
{
// Oracle Specific Search Method
}
然后在您的 DI 容器中更改行
services.AddTransient<IRepositoryBase, SqlRepository>();
至
services.AddTransient<IRepositoryBase, OracleRepository>();
并且您已经通过添加 1 个新的 DB 类,然后在启动时更改 1 行来切换数据库实现,这让您的缓存行为单独存在。
上面讨论了切换基础数据库,但您当然也可以更改级别,因此CachedRepository
可以切换任何实现IRepository
接口的东西,因此您也可以在该层中获得灵活性。
从我读到的你的问题,我想我明白了,这似乎可以解决你的问题。不再有循环依赖。
如果没有请评论,希望这有帮助!
推荐阅读
- angular6 - HTML在选择中没有绑定
- excel - 获取相邻列中最近的非空白单元格的行索引(Excel)
- ambari - ambari server 2.7.3 在步骤 3 上安装主机错误
- android - Android Studio 布局编辑器不显示任何建议
- javascript - 我应该有一个简单地将参数传递给另一个函数的包装函数,还是直接分配另一个函数?
- python - 隐藏后显示关闭按钮(x)(QTabBar)
- android - Android Pie - 通宵服务一直被杀死
- java - java.net.SocketTimeoutException 在 Java 中的集成测试中,同时使用带有 Junit 的 Spring Boot 使用 Wiremock
- excel - 在excel中识别行或列的添加或删除
- node.js - 尝试设置 react.js 环境,不工作