【问题标题】:How to apply decorators with ASP.NET Core Dependency Injection如何使用 ASP.NET Core 依赖注入来应用装饰器
【发布时间】:2016-08-03 00:33:12
【问题描述】:

在 ASP.NET MVC 5 应用程序上,我有以下 StructureMap 配置:

cfg.For(typeof(IRequestHandler<,>)).DecorateAllWith(typeof(MediatorPipeline<,>));

有人知道如何使用 ASP.NET Core IOC 进行此配置吗?

【问题讨论】:

  • 只需使用Scrutor。请参阅下面的答案。

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


【解决方案1】:

开箱即用的 IoC 容器不支持装饰模式或自动发现,据我所知,这是“设计使然”。

这个想法是提供一个开箱即用的基本 IoC 结构,或者可以插入其他 IoC 容器以扩展默认功能。

因此,如果您需要任何高级功能(支持特定构造函数、自动注册实现接口或注入装饰器和拦截器的所有类型),您必须自己编写或使用提供此功能的 IoC 容器。

【讨论】:

    【解决方案2】:

    使用Scrutor。只需安装nuget 包,然后执行以下操作。

    services.AddSingleton<IGreeter, Greeter>();
    services.Decorate<IGreeter, GreeterLogger>();
    services.Decorate<IGreeter, GreeterExceptionHandler>();
    

    顺序很重要。在上面,GreeterLogger 装饰了 Greeter。并且 GreeterExceptionHandler 装饰了 GreeterLogger。

    如果您需要更多信息,请查看thisthis

    【讨论】:

      【解决方案3】:

      这个workaround 不会将装饰器应用于一个类型的所有实例,而是使用扩展方法将装饰器逻辑抽象到另一个文件中。

      定义装饰器结构如:

      public static class QueryHandlerRegistration
      {
          public static IServiceCollection RegisterQueryHandler<TQueryHandler, TQuery, TResult>(
              this IServiceCollection services) 
              where TQuery : IQuery<TResult>
              where TQueryHandler : class, IQueryHandler<TQuery, TResult>
          {
              services.AddTransient<TQueryHandler>();
              services.AddTransient<IQueryHandler<TQuery, TResult>>(x =>
                  new LoggingDecorator<TQuery, TResult>(x.GetService<ILogger<TQuery>>(), x.GetService<TQueryHandler>()));
              return services;
          }
      }
      

      然后这样称呼它:

      services.AddMvc();
      // Add application services.
      services.AddTransient<IEmailSender, AuthMessageSender>();
      services.AddTransient<ISmsSender, AuthMessageSender>();
      
      services.RegisterQueryHandler<FindThingByIdQueryHandler, FindThingByIdQuery, Thing>();
      

      还有 Scrutor 包正在开发中。

      【讨论】:

      • Scutor 的提及非常有用。那里的图书馆不错。令人印象深刻的是,他们设法使用描述符类的标准注册来创建整个机制。
      • 请注意,当 DI 作用域结束时,Scrutor 目前不支持在装饰对象上调用 Dispose。我为此在 GitHub 上提交了一个问题,希望他们最终会修复它:github.com/khellang/Scrutor/issues/91
      【解决方案4】:

      在我的blogpost 中,我描述了一个相对简单的扩展方法是如何轻松解决这个问题的。这是该帖子中的一个示例,它显示了装饰器配置的外观:

      services.AddDecorator<IEmailMessageSender, EmailMessageSenderWithRetryDecorator>(decorateeServices =>
          {
              decorateeServices.AddScoped<IEmailMessageSender, SmtpEmailMessageSender>();
          });
      

      【讨论】:

        【解决方案5】:

        另一个例子

        services.AddTransient<Greeter>();
        services.AddTransient<IGreeter>(g=>
           ActivatorUtilities.CreateInstance<GreeterLogger>(g,g.GetRequiredServices<Greeter>())
        );
        

        或通用

        private static void AddTransientDecorated<TInterface,TService,TDecorator>(this IServiceCollection services)
        {
            services.AddTransient(typeof(TService));
            services.AddTransient(typeof(TInterface), p => ActivatorUtilities.CreateInstance<TDecorator>(p, p.GetRequiredService<TService>()));
        }
        

        其他信息.NET Core DI, ways of passing parameters to constructor

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-09-27
          • 2018-08-07
          • 2016-04-04
          • 1970-01-01
          • 1970-01-01
          • 2016-02-08
          • 1970-01-01
          • 2018-10-17
          相关资源
          最近更新 更多