在ASP.NET中使用依赖注入和工厂模式传递服务 [英] Passing Services using Dependency Injection and Factory Pattern in ASP.NET
问题描述
我正在使用ASP.NET Core,我知道框架已经提供了这种Logging机制,但是用它来说明我的问题.
I am using ASP.NET Core, I know that such Logging mechanism is already provided by the framework, but using this to illustrate my problem.
由于我不知道日志记录的类型(因为它存储在DB中),因此我正在使用某种Factory模式来构建Logger类.
I am using kind of Factory pattern to build the Logger class, since I don't know the type of logging (because it is stored in DB).
ILogger合同
Log(string msg)
然后,基于从数据库传递的参数创建Logger后,LoggerFactory将返回ILogger:
Then LoggerFactory will return an ILogger after creating a Logger based on param passed from DB:
public class LoggerFactory
{
public static Contracts.ILogger BuildLogger(LogType type)
{
return GetLogger(type);
}
//other code is omitted, GetLogger will return an implementation of the related logger
现在,当我需要使用Logger时,必须以这种方式进行操作:
Now, when I need to use the Logger I have to do it in this way:
public class MyService
{
private ILogger _logger
public MyService()
{
_logger = LoggerFactory.BuildLogger("myType");
}
但是,我打算保留我的类而不进行任何实例化,我需要在MyService中使用Constructor DI,并且需要在Startup上注入所有依赖项:
But, I intend to keep my classes without any instantiation, I need to use Constructor DI in MyService and I need to inject all the dependencies on Startup:
services.AddTransient<Contracts.ILogger, LoggerFactory.BuildLogger("param") > ();
但是这行不通,我们需要通过一个具体的实现. 如何使用DI进行这项工作,是否有更好的方法来实现呢?
But this will not work this we need to pass a concrete implementation. How to make that work using DI, is there a better approach for implementing that?
推荐答案
您的方法有两个错误:
- 您的服务取决于具体的
LoggerFactory
类型,这是依赖反转原则的违反. - 进行此额外的初始化可能会使构建对象图不可靠,而注入构造函数应简单.
- 它掩盖了
ILogger
是您的消费者所依赖的真实服务的事实.这使系统更难测试,更难维护,并使对象图分析变得复杂. - 使用工厂是一种气味,因为工厂从来都不是正确的解决方案.
- Your services depend on the concrete
LoggerFactory
type which is a Dependency Inversion Principle violation. - Doing this extra initialization can make building the object graph unreliable, while injection constructors should be simple.
- It hides the fact that the
ILogger
is the real service that your consumer depends upon. This makes the system harder to test, harder to maintain, and complicates object graph analysis. - The use of a factory is a smell, since factories are hardly ever the right solution.
相反,您的服务应如下所示:
Instead, your service should look as follows:
public class MyService
{
private ILogger _logger;
public MyService(ILogger logger)
{
_logger = logger;
}
}
这大大简化了所有依赖ILogger
的消费者.这也意味着,为MyService
获取正确的ILogger
成为组成根,这是掌握此知识的正确位置.
This dramatically simplifies all consumers that depend upon ILogger
. This also means that getting the right ILogger
for MyService
becomes a responsibility of the Composition Root, which is the correct place to have this knowledge.
但是,这确实意味着您可能需要从ASP.NET Core的内置DI容器转移到功能更丰富的DI库,因为内置容器无法进行上下文感知的注册ILogger
,同时使库也自动关联其他构造函数依赖项.
It does mean however that you might need to move away from the built-in DI container of ASP.NET Core to a more feature rich DI library, because the built-in container is not capable of making a context aware registration for ILogger
while having the library auto-wire other constructor dependencies as well.
使用ASP.NET Core DI容器,您只能使用委托手动连接服务.例如:
With the ASP.NET Core DI container, you can only hand-wire your services using a delegate. For instance:
services.AddTransient<MyService>(c => new MyService(
BuildLogger(typeof(MyService).Name),
c.GetRequiredService<ISomeOtherDependency>(),
c.GetRequiredService<IYetAnotherOne>());
这篇关于在ASP.NET中使用依赖注入和工厂模式传递服务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!