【问题标题】:Injecting a logger with constructor dependencies注入具有构造函数依赖项的记录器
【发布时间】:2017-02-06 07:03:30
【问题描述】:

我正在尝试重构一些代码以通过 startup.cs 中的映射服务使用 .NET Core 依赖项注入。我想在这里注入一个 IRequestDatabaseLogger 而不是更新它。但是,它需要构造函数中的上下文。我怎样才能做到这一点?甚至没有 DI 框架甚至有可能吗?

    public class ActionFilter : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext context)
        {
            var requestDatabaseLogger = new RequestDatabaseLogger(context);
            long logId = requestDatabaseLogger.Log();

            context.HttpContext.AddCurrentLogId(logId);

            base.OnActionExecuting(context);
        }
   }

【问题讨论】:

  • 防止在属性中做任何有用的事情。属性应该是被动的,正如herehere 解释的那样。
  • 我认为您的意思是 避免 不是防止(做任何有用的事情)...

标签: c# dependency-injection asp.net-core


【解决方案1】:

但是它需要构造函数中的上下文。

让应用程序组件的构建依赖于运行时数据是一种反模式,如here 所述。那篇文章描述了如何解决这些问题。

在您的情况下,这可能意味着您的组件应该依赖于 ASP.NET Core 的 IHttpContextAccessor 抽象,这是参考文章中描述的模式。

或者,如文章中所述,您可以使用它的Log 方法将所需的运行时数据传递给记录器。

【讨论】:

    【解决方案2】:

    您应该使用 TypeFilter 来实现这一点,并将具有依赖关系的过滤器(在本例中为记录器或上下文)包装在过滤器内。我在MSDN Article on ASP.NET Core Filters 中展示了一个详细的示例。相关源代码为here(查看ValidateAuthorExists 过滤器)。

    这可能是您的场景中的样子:

    public class MyFilterAttribute : TypeFilterAttribute
    {
        public MyFilterAttribute():base(typeof(MyFilterImpl))
        {
        }
    
        private class MyFilterImpl : IAsyncActionFilter
        {
            public MyFilterImpl( *inject dependencies here*)
            {}
        }
    }
    

    这是您可以在 .NET Core 中使用属性同时仍将依赖项注入底层操作过滤器的方式。我还在 DevIQ.com 上即将发布的 ASP.NET Core 快速入门课程中介绍了这一点(请在本月底查看)。

    【讨论】:

      【解决方案3】:

      在构造函数中注入RequestDatabaseLoggerFactory,可用于创建RequestDatabaseLogger实例。

      public interface IRequestDatabaseLoggerFactory {
          IRequestDatabaseLogger Create(ActionExecutingContext context);
      }
      public class RequestDatabaseLoggerFactory : IRequestDatabaseLoggerFactory {
          public IRequestDatabaseLogger Create(ActionExecutingContext context) {
              return new RequestDatabaseLogger(context);
          }
      }
      
      public class ActionFilter : ActionFilterAttribute
      {
          public ActionFilter(IRequestDatabaseLoggerFactory factory) {
              _factory = factory;
          }
      
          private readonly IRequestDatabaseLoggerFactory _factory;
      
          public override void OnActionExecuting(ActionExecutingContext context)
          {
              var requestDatabaseLogger = _factory.Create(context);
              long logId = requestDatabaseLogger.Log();
      
              context.HttpContext.AddCurrentLogId(logId);
      
              base.OnActionExecuting(context);
          }
      

      }

      【讨论】:

      • 我建议不要使用此处所示的工厂抽象,如 here 所述。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-02-02
      • 2020-10-24
      • 1970-01-01
      • 2016-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-17
      相关资源
      最近更新 更多