在ASP.NET中使用依赖注入和工厂模式传递服务

Hus*_*man 4 c# asp.net-mvc dependency-injection factory-pattern asp.net-core

我正在使用ASP.NET Core,我知道框架已经提供了这样的Logging机制,但是使用它来说明我的问题.

我正在使用一种Factory模式来构建Logger类,因为我不知道日志记录的类型(因为它存储在DB中).

ILogger合同

Log(string msg)
Run Code Online (Sandbox Code Playgroud)

然后,在根据从DB传递的参数创建Logger之后,LoggerFactory将返回ILogger:

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
Run Code Online (Sandbox Code Playgroud)

现在,当我需要使用Logger时,我必须这样做:

  public class MyService
{
    private ILogger _logger
    public MyService()
    {
        _logger = LoggerFactory.BuildLogger("myType");
    }
Run Code Online (Sandbox Code Playgroud)

但是,我打算在没有任何实例化的情况下保留我的类,我需要在MyService中使用Constructor DI,我需要在Startup上注入所有依赖项:

    services.AddTransient<Contracts.ILogger, LoggerFactory.BuildLogger("param") > ();
Run Code Online (Sandbox Code Playgroud)

但这不起作用,我们需要通过一个具体的实现.如何使用DI来完成这项工作,是否有更好的方法来实现它?

Ste*_*ven 16

您的方法中存在一些错误:

相反,您的服务应如下所示:

public class MyService
{
    private ILogger _logger;
    public MyService(ILogger logger)
    {
        _logger = logger;
    }
}
Run Code Online (Sandbox Code Playgroud)

这大大简化了所有依赖的消费者ILogger.这也意味着,获得正确ILoggerMyService成为的责任组成的根,这是有这方面的知识的正确位置.

然而,这确实意味着你可能需要从移开内置ASP.NET核心的功能更丰富DI库DI容器,因为内置容器不能够使上下文感知登记的ILogger,同时具有库自动连接其他构造函数依赖项.

使用ASP.NET Core DI容器,您只能使用委托手动连接服务.例如:

services.AddTransient<MyService>(c => new MyService(
    BuildLogger(typeof(MyService).Name),
    c.GetRequiredService<ISomeOtherDependency>(),
    c.GetRequiredService<IYetAnotherOne>());
Run Code Online (Sandbox Code Playgroud)

  • @FabricioKoch:我不确定我是否跟着你.除此之外,我不建议在这里引入通用抽象,因为`MyService`对这种泛型类型完全不感兴趣; 它只是想记录.因此,组合根的问题是提供正确的类型,而不是消费者. (2认同)
  • @ h.salman每个应用程序都包含一个合成根。最好是将框架的ILogger抽象隐藏在特定于应用程序的抽象背后,如[此处](/sf/ask/395277431/)所述,并实现[此处]所描述的MS.Extensions.Logging适配器。 (/sf/answers/2772704021/)。[本文档](https://simpleinjector.readthedocs.io/en/latest/advanced.html#context-based-injection)解释了如何使用Simple Injector连接该适配器。如果您想了解如何使用Ninject或Autofac进行连接,则必须使用Google。 (2认同)