BLa*_*ars 9 .net dependency-injection asp.net-core
我是使用.NETCore的DI模式的新手,我无法将连接字符串连接到DAL.
我通过接受的答案和随后的评论遵循了这个帖子中给出的建议.
这是我的基类
public class BaseRepository : IRepository<IDataModel>
{
private readonly IConfiguration config;
public BaseRepository(IConfiguration config)
{
this.config = config;
}
public string GetSQLConnectionString()
{
return config["Data:DefaultConnetion:ConnectionString"];
}
Run Code Online (Sandbox Code Playgroud)
这是继承基类的存储库类的片段
public class PrivacyLevelRepository : BaseRepository, IRepository<PrivacyLevelDM>
{
public PrivacyLevelRepository(IConfiguration config) : base(config) { }
public void Add(PrivacyLevelDM dataModel)
{
...
}
}
Run Code Online (Sandbox Code Playgroud)
这是在我的startup.cs中
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc();
services.AddScoped<IRepository<IDataModel>>(c => new BaseRepository(Configuration));
}
Run Code Online (Sandbox Code Playgroud)
但是,在我的服务层中,存储库类的实例化仍然要求(IConfiguration配置)作为参数传递.
PrivacyLevelRepository repo = new PrivacyLevelRepository();
Run Code Online (Sandbox Code Playgroud)
如何将IConfiguration直接加载到我的DAL,而不必从Controller> BLL> DAL传递它.这似乎非常低效,而且不正确.因为DAL应该确定对象的连接,而不是控制器或服务层.他们应该不知道数据源,不是吗?
我认为这很简单,我只是没有在DI/IoC范例中看到,但我无法弄明白.
编辑:我没有使用Entity Framework,而是使用自定义数据层.
Thanx任何帮助.
pok*_*oke 11
您可以使用配置框架遵循选项模式.这允许您定义包含配置设置(静态类型)的自定义类型,同时仅限于实际的相关配置.
你可以像这样使用它:
public void ConfigureServices(IServiceCollection services)
{
// register the `Data:DefaultConnection` configuration section as
// a configuration for the `DatabaseOptions` type
services.Configure<DatabaseOptions>(Configuration.GetSection("Data:DefaultConnection"));
// register your database repository
// note that we don’t use a custom factory where we create the object ourselves
services.AddScoped<IRepository<IDataModel>, BaseRepository>();
}
Run Code Online (Sandbox Code Playgroud)
这假定DatabaseOptions
类似这样的类型:
public class DatabaseOptions
{
public string ConnectionString { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
然后,你可以DatabaseOptions
注入你的BaseRepository
:
public class BaseRepository
{
private readonly DatabaseOptions _options;
public BaseRepository(IOptions<DatabaseOptions> databaseOptions)
{
_options = databaseOptions.Value;
}
}
Run Code Online (Sandbox Code Playgroud)
当然,如果你有这种子类型BaseRepository
,你也需要注册它们并将选项传递给基类:
// register the repository as well in the `ConfigureServices` method
services.AddScoped<PrivacyLevelRepository>();
Run Code Online (Sandbox Code Playgroud)
public class PrivacyLevelRepository : BaseRepository, IRepository<PrivacyLevelDM>
{
public PrivacyLevelRepository(IOptions<DatabaseOptions> databaseOptions)
: base(databaseOptions)
{ }
}
Run Code Online (Sandbox Code Playgroud)
我正在实例化并使用像我一直拥有的回购.我不知道如何使用我没有实例化的类.我如何让这个对象知道它取决于
PrivacyLevelRepository
?Run Code Online (Sandbox Code Playgroud)PrivacyLevelRepository repo = new PrivacyLevelRepository(); returnValue = repo.GetAllByDomainID(DomainID).ToList(); return returnValue;
您似乎还不了解依赖注入背后的想法.依赖注入及其基本原理Inversion of Control简单地说就是避免使用new
创建对象.您没有主动依赖于实现(在您的示例中PrivacyLevelRepository
),而是放弃了责任,只依靠外部系统为您提供所需的依赖项.
因此,不是创建新的PrivacyLevelRepository
,而是注入由其他地方创建的实例.这就失去了对依赖项实现的耦合.一个非常实际的例子是如何PrivacyLevelRepository
依赖IOptions<DatabaseOptions>
.作为该存储库的使用者,您不需要关心如何使这样的对象能够创建存储库实例.您甚至不需要知道如何创建存储库实例.
因此,您的消费者PrivacyLevelRepository
应该遵循与存储库本身相同的想法:存储库不知道如何获取这些数据库选项; 它只取决于构造实体传递这样的对象.而我的消费者,我假设一个控制器,应该这样做:
public class MyController
{
private readonly PrivacyLevelRepository _privacyLevelRepository;
public MyController(PrivacyLevelRepository privacyLevelRepository)
{
// instead of *creating* a repository, we just expect to get one
_privacyLevelRepository = privacyLevelRepository;
}
public IActionResult SomeRoute()
{
var domainId = "whatever";
var data = _privacyLevelRepository.GetAllByDomainID(domainId).ToList();
return View(data);
}
}
Run Code Online (Sandbox Code Playgroud)
当然,某些事情必须在某些时候创建依赖关系.但是如果你完全接受依赖注入 - 哪个ASP.NET Core不仅非常容易,而且还需要你这么做才能完全工作 - 那么你就不需要关心那个部分了.您只需在ConfigureServices
方法中注册类型,然后期望在您需要的地方满足依赖项.
有关更多信息,请务必查看文档的依赖注入章节.
你不应该被注入IConfiguration
在所有到您的类.在IConfiguration
允许访问所有的配置值,而一类只需要一个(或几个人).注入IConfiguration
是与Service Locator反模式相同的配置(但用于解析配置值).它隐藏了消费者使用的实际配置值,使得类更难以使用和测试.
最重要的是,这个模型使得验证配置文件的正确性变得更加困难,因为只有在应用程序中第一次请求时,才能验证各个配置值,这可能是许多鼠标"点击"到应用程序中.
解决方案是在启动时加载并验证配置值,并仅注入一个类所需的配置值,仅此而已.这允许系统快速失败并从类的API中非常清楚它需要什么配置值.显然,您可以将配置值一起打包到一个Value Object中,而.NET Core使这更加简单,这非常好.
您应该防止的另一件事是使用基类.基类经常变得不断变化,并且正在增加代码块,其中包含辅助方法和交叉关注点.由于对基类的依赖性很强,它们的衍生物变得更难测试.
当您将连接字符串直接注入到您的中时PrivacyLevelRepository
,不需要具有a的基类GetSQLConnectionString
,因为存储库已经具有可用的连接字符串.可能还有其他原因导致您拥有此基类,例如因为您想要记录或实现安全功能,但我的建议是不要使用基类.取而代之的是使用装饰和拦截,因为它允许保持"衍生"忽视这些横切关注的问题,甚至允许更加模块化和灵活的系统.
UPDATE
这是配置它的方法
string conStr = config["Data:DefaultConnetion:ConnectionString"];
services.AddScoped<IRepository<IDataModel>>(c => new PrivacyLevelRepository(conStr));
Run Code Online (Sandbox Code Playgroud)
不管你做什么,不要让你的应用程序组件的依赖IOptions<T>
,因为它有一些很糟糕的后果,如所描述这里.
归档时间: |
|
查看次数: |
7716 次 |
最近记录: |